rnd-20061029-1-src
[rocksndiamonds.git] / src / libgame / gadgets.c
index 678107c6d5ad009319c080373b0ce1260dee41ae..7c140cbedffbaf8d7cb742cd6cc5f3e741327b7c 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Artsoft Retro-Game Library                               *
 *----------------------------------------------------------*
-* (c) 1994-2002 Artsoft Entertainment                      *
+* (c) 1994-2006 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
@@ -71,20 +71,24 @@ static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my,
   struct GadgetInfo *gi;
 
   /* first check for scrollbars in case of mouse scroll wheel button events */
-  if (button == 4 || button == 5)
+  if (IS_WHEEL_BUTTON(button))
   {
-#if 0
-    printf("WHOA! SCROLL WHEEL DETECTED [%d]\n", button);
-#endif
+    /* real horizontal wheel or vertical wheel with modifier key pressed */
+    boolean check_horizontal = (IS_WHEEL_BUTTON_HORIZONTAL(button) ||
+                               GetKeyModState() & KMOD_Shift);
 
+    /* check for the first active scrollbar with matching mouse wheel area */
     for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
     {
       if (gi->mapped && gi->active &&
-         gi->type & GD_TYPE_SCROLLBAR)
+         ((gi->type & GD_TYPE_SCROLLBAR_HORIZONTAL && check_horizontal) ||
+          (gi->type & GD_TYPE_SCROLLBAR_VERTICAL && !check_horizontal)) &&
+         mx >= gi->wheelarea.x && mx < gi->wheelarea.x + gi->wheelarea.width &&
+         my >= gi->wheelarea.y && my < gi->wheelarea.y + gi->wheelarea.height)
        return gi;
     }
 
-    /* no active scrollbar found -- ignore this button event */
+    /* no active scrollbar found -- ignore this scroll wheel button event */
     return NULL;
   }
 
@@ -764,20 +768,14 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
        break;
 
       case GDI_ACTIVE:
-       /* take care here: "boolean" is typedef'ed as "unsigned char",
-          which gets promoted to "int" */
        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" */
        gi->checked = (boolean)va_arg(ap, int);
        break;
 
@@ -995,6 +993,22 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
        gi->scrollbar.item_position = va_arg(ap, int);
        break;
 
+      case GDI_WHEEL_AREA_X:
+       gi->wheelarea.x = va_arg(ap, int);
+       break;
+
+      case GDI_WHEEL_AREA_Y:
+       gi->wheelarea.y = va_arg(ap, int);
+       break;
+
+      case GDI_WHEEL_AREA_WIDTH:
+       gi->wheelarea.width = va_arg(ap, int);
+       break;
+
+      case GDI_WHEEL_AREA_HEIGHT:
+       gi->wheelarea.height = va_arg(ap, int);
+       break;
+
       case GDI_CALLBACK_INFO:
        gi->callback_info = va_arg(ap, gadget_function);
        break;
@@ -1401,6 +1415,7 @@ void ClickOnGadget(struct GadgetInfo *gi, int button)
 boolean HandleGadgets(int mx, int my, int button)
 {
   static unsigned long pressed_delay = 0;
+  static unsigned long pressed_delay_value = GADGET_FRAME_DELAY;
   static int last_button = 0;
   static int last_mx = 0, last_my = 0;
   static int pressed_mx = 0, pressed_my = 0;
@@ -1480,7 +1495,7 @@ boolean HandleGadgets(int mx, int my, int button)
        (gadget_pressed_inside_select_line && !mouse_inside_select_area)))
   {
     struct GadgetInfo *gi = last_gi;
-    boolean gadget_changed = (gi->event_mask & GD_EVENT_TEXT_LEAVING);
+    boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_LEAVING) != 0);
 
     /* check if text gadget has changed its value */
     if (gi->type & GD_TYPE_TEXT_INPUT)
@@ -1516,7 +1531,7 @@ boolean HandleGadgets(int mx, int my, int button)
     (button != 0 && last_gi != NULL && new_gi == last_gi);
 
   gadget_pressed_delay_reached =
-    DelayReached(&pressed_delay, GADGET_FRAME_DELAY);
+    DelayReached(&pressed_delay, pressed_delay_value);
 
   gadget_released =            (release_event && last_gi != NULL);
   gadget_released_inside =     (gadget_released && new_gi == last_gi);
@@ -1667,8 +1682,6 @@ boolean HandleGadgets(int mx, int my, int button)
     last_info_gi = new_gi;
   }
 
-#if 1
-
   gadget_draggable = (gi && gi->type & GD_TYPE_SCROLLBAR);
 
   /* reset drag position for newly pressed scrollbar to "not dragging" */
@@ -1688,14 +1701,29 @@ boolean HandleGadgets(int mx, int my, int button)
   if ((gadget_pressed) ||
       (gadget_pressed_repeated && gadget_pressed_delay_reached))
   {
+    if (gadget_pressed)                /* gadget pressed the first time */
+    {
+      /* initialize delay counter */
+      DelayReached(&pressed_delay, 0);
+
+      /* start gadget delay with longer delay after first click on gadget */
+      pressed_delay_value = GADGET_FRAME_DELAY_FIRST;
+    }
+    else                       /* gadget hold pressed for some time */
+    {
+      /* after first repeated gadget click, continue with shorter delay value */
+      pressed_delay_value = GADGET_FRAME_DELAY;
+    }
+
     if (gi->type & GD_TYPE_SCROLLBAR && !gadget_dragging)
     {
       int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx    : my);
       int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y);
+      int slider_start = gpos + gi->scrollbar.position;
+      int slider_end   = gpos + gi->scrollbar.position + gi->scrollbar.size - 1;
+      boolean inside_slider = (mpos >= slider_start && mpos <= slider_end);
 
-      if (button > 3 ||
-         mpos < gpos + gi->scrollbar.position ||
-         mpos >= gpos + gi->scrollbar.position + gi->scrollbar.size)
+      if (IS_WHEEL_BUTTON(button) || !inside_slider)
       {
        /* click scrollbar one scrollbar length up/left or down/right */
 
@@ -1704,10 +1732,13 @@ boolean HandleGadgets(int mx, int my, int button)
        int item_steps = gs->items_visible - 1;
        int item_direction = (mpos < gpos + gi->scrollbar.position ? -1 : +1);
 
-       if (button > 3)
+       if (IS_WHEEL_BUTTON(button))
        {
-         item_steps = 3;
-         item_direction = (button == 4 ? -1 : +1);
+         boolean scroll_single_step = ((GetKeyModState() & KMOD_Alt) != 0);
+
+         item_steps = (scroll_single_step ? 1 : DEFAULT_WHEEL_STEPS);
+         item_direction = (button == MB_WHEEL_UP ||
+                           button == MB_WHEEL_LEFT ? -1 : +1);
        }
 
        changed_position = FALSE;
@@ -1750,8 +1781,6 @@ boolean HandleGadgets(int mx, int my, int button)
     }
   }
 
-#endif
-
   if (gadget_pressed)
   {
     if (gi->type == GD_TYPE_CHECK_BUTTON)
@@ -1782,10 +1811,11 @@ boolean HandleGadgets(int mx, int my, int button)
     {
       int mpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx    : my);
       int gpos = (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? gi->x : gi->y);
+      int slider_start = gpos + gi->scrollbar.position;
+      int slider_end   = gpos + gi->scrollbar.position + gi->scrollbar.size - 1;
+      boolean inside_slider = (mpos >= slider_start && mpos <= slider_end);
 
-      if (button >= 1 && button <= 3 &&
-         mpos >= gpos + gi->scrollbar.position &&
-         mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
+      if (!IS_WHEEL_BUTTON(button) && inside_slider)
       {
        /* start dragging scrollbar */
        gi->scrollbar.drag_position =
@@ -1806,9 +1836,6 @@ boolean HandleGadgets(int mx, int my, int button)
     gi->event.button = button;
     gi->event.off_borders = FALSE;
 
-    /* initialize delay counter */
-    DelayReached(&pressed_delay, 0);
-
     if (gi->event_mask & GD_EVENT_PRESSED)
       gi->callback_action(gi);
   }
@@ -1817,14 +1844,8 @@ boolean HandleGadgets(int mx, int my, int button)
   {
     gi->event.type = GD_EVENT_PRESSED;
 
-#if 1
     if (gi->event_mask & GD_EVENT_REPEATED && gadget_pressed_delay_reached)
       gi->callback_action(gi);
-#else
-    if (gi->event_mask & GD_EVENT_REPEATED &&
-       DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
-      gi->callback_action(gi);
-#endif
   }
 
   if (gadget_moving)
@@ -1940,9 +1961,7 @@ boolean HandleGadgets(int mx, int my, int button)
     if (gi->type & GD_TYPE_SCROLLBAR)
       DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
 
-#if 1
     gi->state = GD_BUTTON_UNPRESSED;
-#endif
     gi->event.type = GD_EVENT_RELEASED;
 
     if (gi->event_mask & GD_EVENT_RELEASED &&
@@ -1985,7 +2004,7 @@ boolean HandleGadgetsKeyInput(Key key)
 
   if (key == KSYM_Return)      /* valid for both text input and selectbox */
   {
-    boolean gadget_changed = (gi->event_mask & GD_EVENT_TEXT_RETURN);
+    boolean gadget_changed = ((gi->event_mask & GD_EVENT_TEXT_RETURN) != 0);
 
     if (gi->type & GD_TYPE_TEXT_INPUT)
     {