rnd-20030823-2-src
[rocksndiamonds.git] / src / libgame / gadgets.c
index 89276bcdbb1561d9d4c3cad38f03f829a1d8d077..7b7041200098360db6ee4b4aadc35decd462da5e 100644 (file)
@@ -22,6 +22,7 @@
 /* values for DrawGadget() */
 #define DG_UNPRESSED           0
 #define DG_PRESSED             1
+
 #define DG_BUFFERED            0
 #define DG_DIRECT              1
 
@@ -68,7 +69,7 @@ void DUMP_GADGET_MAP_STATE()
 {
   struct GadgetInfo *gi = gadget_list_first_entry;
 
-  while (gi)
+  while (gi != NULL)
   {
     printf("-XXX-1-> '%s': %s\n",
           gi->info_text, (gi->mapped ? "mapped" : "not mapped"));
@@ -80,22 +81,28 @@ void DUMP_GADGET_MAP_STATE()
 
 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
 {
-  struct GadgetInfo *gi = gadget_list_first_entry;
+  struct GadgetInfo *gi;
 
-  while (gi)
+  /* open selectboxes may overlap other active gadgets, so check them first */
+  for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
   {
     if (gi->mapped && gi->active &&
-       ((mx >= gi->x && mx < gi->x + gi->width &&
-         my >= gi->y && my < gi->y + gi->height) ||
-        (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open &&
-         mx >= gi->selectbox.x && mx < gi->selectbox.x+gi->selectbox.width &&
-         my >= gi->selectbox.y && my < gi->selectbox.y+gi->selectbox.height)))
-      break;
+       gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open &&
+       mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width &&
+       my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
+      return gi;
+  }
 
-    gi = gi->next;
+  /* check all other gadgets */
+  for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
+  {
+    if (gi->mapped && gi->active &&
+       mx >= gi->x && mx < gi->x + gi->width &&
+       my >= gi->y && my < gi->y + gi->height)
+      return gi;
   }
 
-  return gi;
+  return NULL;
 }
 
 static void default_callback_info(void *ptr)
@@ -584,6 +591,12 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
        gi->active = (boolean)va_arg(ap, int);
        break;
 
+      case GDI_DIRECT_DRAW:
+       /* take care here: "boolean" is typedef'ed as "unsigned char",
+          which gets promoted to "int" */
+       gi->direct_draw = (boolean)va_arg(ap, int);
+       break;
+
       case GDI_CHECKED:
        /* take care here: "boolean" is typedef'ed as "unsigned char",
           which gets promoted to "int" */
@@ -822,6 +835,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
     int border_xsize = gi->border.xsize;
     int border_ysize = gi->border.ysize;
     int button_size = gi->border.xsize_selectbutton;
+    int bottom_screen_border = gfx.sy + gfx.sysize - font_height;
     Bitmap *src_bitmap;
     int src_x, src_y;
 
@@ -842,10 +856,10 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
 
     gi->selectbox.x = gi->x;
     gi->selectbox.y = gi->y + gi->height;
-    if (gi->selectbox.y + gi->selectbox.height > gfx.real_sy + gfx.full_sysize)
+    if (gi->selectbox.y + gi->selectbox.height > bottom_screen_border)
       gi->selectbox.y = gi->y - gi->selectbox.height;
     if (gi->selectbox.y < 0)
-      gi->selectbox.y = gfx.real_sy + gfx.full_sysize - gi->selectbox.height;
+      gi->selectbox.y = bottom_screen_border - gi->selectbox.height;
 
     getFontCharSource(font_nr, FONT_ASCII_CURSOR, &src_bitmap, &src_x, &src_y);
     src_x += font_width / 2;
@@ -916,7 +930,7 @@ void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
 void RedrawGadget(struct GadgetInfo *gi)
 {
   if (gi->mapped)
-    DrawGadget(gi, gi->state, DG_DIRECT);
+    DrawGadget(gi, gi->state, gi->direct_draw);
 }
 
 struct GadgetInfo *CreateGadget(int first_tag, ...)
@@ -929,6 +943,8 @@ struct GadgetInfo *CreateGadget(int first_tag, ...)
   new_gadget->callback_info = default_callback_info;
   new_gadget->callback_action = default_callback_action;
   new_gadget->active = TRUE;
+  new_gadget->direct_draw = TRUE;
+
   new_gadget->next = NULL;
 
   va_start(ap, first_tag);
@@ -1033,7 +1049,7 @@ static void MultiMapGadgets(int mode)
   static boolean map_state[MAX_NUM_GADGETS];
   int map_count = 0;
 
-  while (gi)
+  while (gi != NULL)
   {
     if ((mode & MULTIMAP_PLAYFIELD &&
         gi->x < gfx.sx + gfx.sxsize) ||
@@ -1124,6 +1140,13 @@ void HandleGadgets(int mx, int my, int button)
   if (gadget_list_first_entry == NULL)
     return;
 
+  /* simulated release of mouse button over last gadget */
+  if (mx == -1 && my == -1 && button == 0)
+  {
+    mx = last_mx;
+    my = last_my;
+  }
+
   /* check which gadget is under the mouse pointer */
   new_gi = getGadgetInfoFromMousePosition(mx, my);
 
@@ -1156,13 +1179,13 @@ void HandleGadgets(int mx, int my, int button)
        gi->text.cursor_position = strlen(gi->text.value);
 
       if (gi->text.cursor_position != old_cursor_position)
-       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+       DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else
     {
       /* if mouse button pressed outside text input gadget, deactivate it */
       CheckRangeOfNumericInputGadget(gi);
-      DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
 
       gi->event.type = GD_EVENT_TEXT_LEAVING;
 
@@ -1185,7 +1208,7 @@ void HandleGadgets(int mx, int my, int button)
       /* if mouse button pressed inside activated selectbox, select value */
       if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
        gi->selectbox.current_index =
-         (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
+         (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
 
       if (gi->selectbox.current_index < 0)
        gi->selectbox.current_index = 0;
@@ -1193,12 +1216,12 @@ void HandleGadgets(int mx, int my, int button)
        gi->selectbox.current_index = gi->selectbox.num_values - 1;
 
       if (gi->selectbox.current_index != old_index)
-       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+       DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else
     {
       /* if mouse button pressed outside selectbox gadget, deactivate it */
-      DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
 
       gi->event.type = GD_EVENT_TEXT_LEAVING;
 
@@ -1231,8 +1254,8 @@ void HandleGadgets(int mx, int my, int button)
       (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);
+      (mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width &&
+       my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height);
   }
   else
   {
@@ -1267,7 +1290,7 @@ void HandleGadgets(int mx, int my, int button)
   if (button == 0 && !release_event)
     gi = new_gi;
 
-  if (gi)
+  if (gi != NULL)
   {
     int last_x = gi->event.x;
     int last_y = gi->event.y;
@@ -1290,7 +1313,7 @@ void HandleGadgets(int mx, int my, int button)
       /* if mouse moving inside activated selectbox, select value */
       if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
        gi->selectbox.current_index =
-         (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
+         (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
 
       if (gi->selectbox.current_index < 0)
        gi->selectbox.current_index = 0;
@@ -1298,7 +1321,7 @@ void HandleGadgets(int mx, int my, int button)
        gi->selectbox.current_index = gi->selectbox.num_values - 1;
 
       if (gi->selectbox.current_index != old_index)
-       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+       DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
   }
 
@@ -1347,7 +1370,7 @@ void HandleGadgets(int mx, int my, int button)
            rgi != gi)
        {
          rgi->checked = FALSE;
-         DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
+         DrawGadget(rgi, DG_UNPRESSED, rgi->direct_draw);
        }
 
        rgi = rgi->next;
@@ -1417,7 +1440,7 @@ void HandleGadgets(int mx, int my, int button)
       }
     }
 
-    DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    DrawGadget(gi, DG_PRESSED, gi->direct_draw);
 
     gi->state = GD_BUTTON_PRESSED;
     gi->event.type = GD_EVENT_PRESSED;
@@ -1445,9 +1468,9 @@ void HandleGadgets(int mx, int my, int button)
     if (gi->type & GD_TYPE_BUTTON)
     {
       if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
-       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+       DrawGadget(gi, DG_PRESSED, gi->direct_draw);
       else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
-       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+       DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
     }
     else if (gi->type & GD_TYPE_SELECTBOX)
     {
@@ -1456,7 +1479,7 @@ void HandleGadgets(int mx, int my, int button)
       /* if mouse moving inside activated selectbox, select value */
       if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
        gi->selectbox.current_index =
-         (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
+         (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
 
       if (gi->selectbox.current_index < 0)
        gi->selectbox.current_index = 0;
@@ -1464,7 +1487,7 @@ void HandleGadgets(int mx, int my, int button)
        gi->selectbox.current_index = gi->selectbox.num_values - 1;
 
       if (gi->selectbox.current_index != old_index)
-       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+       DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else if (gi->type & GD_TYPE_SCROLLBAR)
     {
@@ -1492,7 +1515,7 @@ void HandleGadgets(int mx, int my, int button)
        changed_position = TRUE;
       }
 
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
 
     gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
@@ -1520,7 +1543,7 @@ void HandleGadgets(int mx, int my, int button)
 
     if (deactivate_gadget &&
        !(gi->type & GD_TYPE_TEXTINPUT))            /* text input stays open */
-      DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
 
     gi->state = GD_BUTTON_UNPRESSED;
     gi->event.type = GD_EVENT_RELEASED;
@@ -1532,7 +1555,7 @@ void HandleGadgets(int mx, int my, int button)
   if (gadget_released_off_borders)
   {
     if (gi->type & GD_TYPE_SCROLLBAR)
-      DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
 
     gi->event.type = GD_EVENT_RELEASED;
 
@@ -1540,6 +1563,10 @@ void HandleGadgets(int mx, int my, int button)
        gi->event_mask & GD_EVENT_OFF_BORDERS)
       gi->callback_action(gi);
   }
+
+  /* handle gadgets unmapped/mapped between pressing and releasing */
+  if (release_event && !gadget_released && new_gi)
+    new_gi->state = GD_BUTTON_UNPRESSED;
 }
 
 void HandleGadgetsKeyInput(Key key)
@@ -1557,7 +1584,7 @@ void HandleGadgetsKeyInput(Key key)
     else if (gi->type & GD_TYPE_SELECTBOX)
       gi->selectbox.index = gi->selectbox.current_index;
 
-    DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+    DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
 
     gi->event.type = GD_EVENT_TEXT_RETURN;
 
@@ -1583,30 +1610,30 @@ void HandleGadgetsKeyInput(Key key)
       gi->text.value[cursor_pos] = letter;
       gi->text.cursor_position++;
 
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else if (key == KSYM_Left && cursor_pos > 0)
     {
       gi->text.cursor_position--;
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else if (key == KSYM_Right && cursor_pos < text_length)
     {
       gi->text.cursor_position++;
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else if (key == KSYM_BackSpace && cursor_pos > 0)
     {
       strcpy(text, gi->text.value);
       strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
       gi->text.cursor_position--;
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else if (key == KSYM_Delete && cursor_pos < text_length)
     {
       strcpy(text, gi->text.value);
       strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
   }
   else if (gi->type & GD_TYPE_SELECTBOX)       /* only valid for selectbox */
@@ -1617,12 +1644,12 @@ void HandleGadgetsKeyInput(Key key)
     if (key == KSYM_Up && index > 0)
     {
       gi->selectbox.current_index--;
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
     else if (key == KSYM_Down && index < num_values - 1)
     {
       gi->selectbox.current_index++;
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
   }
 }