--- /src/cvs/allegro/src/gui.c	Thu May  2 00:36:41 2002
+++ gui.c	Tue May  7 18:41:43 2002
@@ -733,6 +733,8 @@
    player->dialog = dialog;
    player->obj = -1;
    player->mouse_obj = -1;
+   player->drag_obj = -1;
+   player->drag_b = 0;
    player->mouse_oz = gui_mouse_z();
    player->mouse_b = gui_mouse_b();
 
@@ -851,6 +853,7 @@
 int update_dialog(DIALOG_PLAYER *player)
 {
    int c, cascii, cscan, ccombo, r, ret, nowhere, z;
+   int x, y, x_part, y_part;
    int new_mouse_b;
 
    if (player->res & D_CLOSE)
@@ -862,6 +865,8 @@
       player->res |= offer_focus(player->dialog, player->mouse_obj, &player->focus_obj, FALSE);
 
       if (player->mouse_obj >= 0) {
+	 r = player->res;
+
 	 /* send press and release messages */
          if ((new_mouse_b & 1) && !(player->mouse_b & 1))
 	    MESSAGE(player->mouse_obj, MSG_LPRESS, new_mouse_b);
@@ -878,6 +883,18 @@
          if (!(new_mouse_b & 2) && (player->mouse_b & 2))
 	    MESSAGE(player->mouse_obj, MSG_RRELEASE, new_mouse_b);
 
+	 if (!(r & D_WANTDRAG) && (player->res & D_WANTDRAG)) {
+            /* dragging is beginning */
+            player->drag_obj = player->mouse_obj;
+            player->drag_b = new_mouse_b;
+            player->dialog[player->drag_obj].flags |= D_DRAGGED;
+	 }
+	 if ((player->drag_obj >= 0) && !(new_mouse_b & player->drag_b)) {
+	    /* dragging is ending */
+            player->dialog[player->drag_obj].flags &= ~D_DRAGGED;
+	    player->drag_obj = -1;
+	    player->res &= ~D_WANTDRAG;
+         }
          player->mouse_b = new_mouse_b;
       }
       else
@@ -926,50 +943,76 @@
 
    player->res &= ~D_USED_CHAR;
 
-   /* need to give the input focus to someone? */
-   if (player->res & D_WANTFOCUS) {
-      player->res ^= D_WANTFOCUS;
-      player->res |= offer_focus(player->dialog, player->obj, &player->focus_obj, FALSE);
-   }
-
-   /* has mouse object changed? */
-   c = find_mouse_object(player->dialog);
-   if (c != player->mouse_obj) {
-      if (player->mouse_obj >= 0) {
-	 player->dialog[player->mouse_obj].flags &= ~D_GOTMOUSE;
-	 MESSAGE(player->mouse_obj, MSG_LOSTMOUSE, 0);
+   /* handle drags specially */
+   if (player->drag_obj >= 0) {
+      /* send a new drag if the mouse moved */
+      x = gui_mouse_x() - player->mouse_ox;
+      y = gui_mouse_y() - player->mouse_oy;
+      player->mouse_ox += x;
+      player->mouse_oy += y;
+      while (x != 0 || y != 0) {
+         x_part = MID(SHRT_MIN, x, SHRT_MAX);
+         y_part = MID(SHRT_MIN, y, SHRT_MAX);
+         MESSAGE(player->drag_obj, MSG_DRAG, ((x_part & 0xffff) << 16) |
+			 (y_part & 0xffff));
+	 x -= x_part; y -= y_part;
       }
-      if (c >= 0) {
-	 player->dialog[c].flags |= D_GOTMOUSE;
-	 MESSAGE(c, MSG_GOTMOUSE, 0);
-      }
-      player->mouse_obj = c; 
-
-      /* move the input focus as well? */
-      if ((gui_mouse_focus) && (player->mouse_obj != player->focus_obj))
-	 player->res |= offer_focus(player->dialog, player->mouse_obj, &player->focus_obj, TRUE);
    }
-
-   /* deal with mouse button clicks */
-   if (new_mouse_b) {
-      player->res |= offer_focus(player->dialog, player->mouse_obj, &player->focus_obj, FALSE);
-
-      if (player->mouse_obj >= 0) {
-	 dclick_time = 0;
-	 dclick_status = DCLICK_START;
-	 player->mouse_ox = gui_mouse_x();
-	 player->mouse_oy = gui_mouse_y();
-
-	 /* send click message */
-	 MESSAGE(player->mouse_obj, MSG_CLICK, new_mouse_b);
+   else {
+      /* need to give the input focus to someone? */
+      if (player->res & D_WANTFOCUS) {
+         player->res ^= D_WANTFOCUS;
+         player->res |= offer_focus(player->dialog, player->obj, &player->focus_obj, FALSE);
+      }
+
+      /* has mouse object changed? */
+      c = find_mouse_object(player->dialog);
+      if (c != player->mouse_obj) {
+         if (player->mouse_obj >= 0) {
+   	    player->dialog[player->mouse_obj].flags &= ~D_GOTMOUSE;
+	    MESSAGE(player->mouse_obj, MSG_LOSTMOUSE, 0);
+         }
+         if (c >= 0) {
+	    player->dialog[c].flags |= D_GOTMOUSE;
+	    MESSAGE(c, MSG_GOTMOUSE, 0);
+         }
+         player->mouse_obj = c; 
+
+         /* move the input focus as well? */
+         if ((gui_mouse_focus) && (player->mouse_obj != player->focus_obj))
+	    player->res |= offer_focus(player->dialog, player->mouse_obj, &player->focus_obj, TRUE);
+      }
+
+      /* deal with mouse button clicks */
+      if (new_mouse_b) {
+         player->res |= offer_focus(player->dialog, player->mouse_obj, &player->focus_obj, FALSE);
+
+         if (player->mouse_obj >= 0) {
+	    dclick_time = 0;
+	    dclick_status = DCLICK_START;
+	    player->mouse_ox = gui_mouse_x();
+	    player->mouse_oy = gui_mouse_y();
+
+	    /* send click message */
+	    MESSAGE(player->mouse_obj, MSG_CLICK, new_mouse_b);
+
+	    if (player->res == D_O_K)
+	       player->click_wait = TRUE;
+	    else if (player->res & D_WANTDRAG) {
+	       /* a drag is just beginning */
+	       player->drag_obj = player->mouse_obj;
+               player->drag_b = new_mouse_b;
+               player->dialog[player->drag_obj].flags |= D_DRAGGED;
+               MESSAGE(player->drag_obj, MSG_DRAG, 0);
+	    }
+         }
+         else
+	    player->res |= dialog_message(player->dialog, MSG_IDLE, 0, &nowhere);
 
 	 if (player->res == D_O_K)
 	    player->click_wait = TRUE;
+         /* goto getout; */  /* to avoid an updating delay */
       }
-      else
-	 player->res |= dialog_message(player->dialog, MSG_IDLE, 0, &nowhere);
-
-      /* goto getout; */  /* to avoid an updating delay */
    }
 
    /* deal with mouse wheel clicks */
@@ -989,105 +1032,108 @@
       /* goto getout; */  /* to avoid an updating delay */
    }
 
-   /* fake joystick input by converting it to key presses */
-   if (player->joy_on)
-      rest(20);
-
-   poll_joystick();
-
-   if (player->joy_on) {
-      if ((!joy[0].stick[0].axis[0].d1) && (!joy[0].stick[0].axis[0].d2) && 
-	  (!joy[0].stick[0].axis[1].d1) && (!joy[0].stick[0].axis[1].d2) &&
-	  (!joy[0].button[0].b) && (!joy[0].button[1].b)) {
-	 player->joy_on = FALSE;
-	 rest(20);
-      }
-      cascii = cscan = 0;
-   }
-   else {
-      if (joy[0].stick[0].axis[0].d1) {
-	 cascii = 0;
-	 cscan = KEY_LEFT;
-	 player->joy_on = TRUE;
-      }
-      else if (joy[0].stick[0].axis[0].d2) {
-	 cascii = 0;
-	 cscan = KEY_RIGHT;
-	 player->joy_on = TRUE;
-      }
-      else if (joy[0].stick[0].axis[1].d1) {
-	 cascii = 0;
-	 cscan = KEY_UP;
-	 player->joy_on = TRUE;
-      }
-      else if (joy[0].stick[0].axis[1].d2) {
-	 cascii = 0;
-	 cscan = KEY_DOWN;
-	 player->joy_on = TRUE;
-      }
-      else if ((joy[0].button[0].b) || (joy[0].button[1].b)) {
-	 cascii = ' ';
-	 cscan = KEY_SPACE;
-	 player->joy_on = TRUE;
+   /* joystick and keyboard stuff is disabled during dragging */
+   if (!(player->res & D_WANTDRAG)) {
+      /* fake joystick input by converting it to key presses */
+      if (player->joy_on)
+         rest(20);
+
+      poll_joystick();
+
+      if (player->joy_on) {
+         if ((!joy[0].stick[0].axis[0].d1) && (!joy[0].stick[0].axis[0].d2) && 
+	     (!joy[0].stick[0].axis[1].d1) && (!joy[0].stick[0].axis[1].d2) &&
+	     (!joy[0].button[0].b) && (!joy[0].button[1].b)) {
+	    player->joy_on = FALSE;
+	    rest(20);
+         }
+         cascii = cscan = 0;
       }
-      else
-	 cascii = cscan = 0;
-   }
+      else {
+         if (joy[0].stick[0].axis[0].d1) {
+	    cascii = 0;
+	    cscan = KEY_LEFT;
+	    player->joy_on = TRUE;
+         }
+         else if (joy[0].stick[0].axis[0].d2) {
+	    cascii = 0;
+	    cscan = KEY_RIGHT;
+	    player->joy_on = TRUE;
+         }
+         else if (joy[0].stick[0].axis[1].d1) {
+	    cascii = 0;
+	    cscan = KEY_UP;
+	    player->joy_on = TRUE;
+         }
+         else if (joy[0].stick[0].axis[1].d2) {
+	    cascii = 0;
+	    cscan = KEY_DOWN;
+	    player->joy_on = TRUE;
+         }
+         else if ((joy[0].button[0].b) || (joy[0].button[1].b)) {
+	    cascii = ' ';
+	    cscan = KEY_SPACE;
+	    player->joy_on = TRUE;
+         }
+         else
+	    cascii = cscan = 0;
+      }
+
+      /* deal with keyboard input */
+      if ((cascii) || (cscan) || (keypressed())) {
+         if ((!cascii) && (!cscan))
+	    cascii = ureadkey(&cscan);
+
+         ccombo = (cscan<<8) | ((cascii <= 255) ? cascii : '^');
+
+         /* let object deal with the key */
+         if (player->focus_obj >= 0) {
+	    MESSAGE(player->focus_obj, MSG_CHAR, ccombo);
+	    if (player->res & D_USED_CHAR)
+	       goto getout;
 
-   /* deal with keyboard input */
-   if ((cascii) || (cscan) || (keypressed())) {
-      if ((!cascii) && (!cscan))
-	 cascii = ureadkey(&cscan);
+	    MESSAGE(player->focus_obj, MSG_UCHAR, cascii);
+	    if (player->res & D_USED_CHAR)
+	       goto getout;
+         }
 
-      ccombo = (cscan<<8) | ((cascii <= 255) ? cascii : '^');
+         /* keyboard shortcut? */
+         for (c=0; player->dialog[c].proc; c++) {
+	    if ((((cascii > 0) && (cascii <= 255) && 
+	          (utolower(player->dialog[c].key) == utolower((cascii)))) ||
+	         ((!cascii) && (player->dialog[c].key == (cscan<<8)))) && 
+	        (!(player->dialog[c].flags & (D_HIDDEN | D_DISABLED)))) {
+	       MESSAGE(c, MSG_KEY, ccombo);
+	       goto getout;
+	    }
+         }
 
-      /* let object deal with the key */
-      if (player->focus_obj >= 0) {
-	 MESSAGE(player->focus_obj, MSG_CHAR, ccombo);
-	 if (player->res & D_USED_CHAR)
+         /* broadcast in case any other objects want it */
+         for (c=0; player->dialog[c].proc; c++) {
+	    if (!(player->dialog[c].flags & (D_HIDDEN | D_DISABLED))) {
+	       MESSAGE(c, MSG_XCHAR, ccombo);
+	       if (player->res & D_USED_CHAR)
+	          goto getout;
+	    }
+         }
+
+         /* pass <CR> or <SPACE> to selected object */
+         if (((cascii == '\r') || (cascii == '\n') || (cascii == ' ')) && 
+	     (player->focus_obj >= 0)) {
+	    MESSAGE(player->focus_obj, MSG_KEY, ccombo);
 	    goto getout;
+         }
 
-	 MESSAGE(player->focus_obj, MSG_UCHAR, cascii);
-	 if (player->res & D_USED_CHAR)
+         /* ESC closes dialog */
+         if (cascii == 27) {
+	    player->res |= D_CLOSE;
+	    player->obj = -1;
 	    goto getout;
-      }
+         }
 
-      /* keyboard shortcut? */
-      for (c=0; player->dialog[c].proc; c++) {
-	 if ((((cascii > 0) && (cascii <= 255) && 
-	       (utolower(player->dialog[c].key) == utolower((cascii)))) ||
-	      ((!cascii) && (player->dialog[c].key == (cscan<<8)))) && 
-	     (!(player->dialog[c].flags & (D_HIDDEN | D_DISABLED)))) {
-	    MESSAGE(c, MSG_KEY, ccombo);
-	    goto getout;
-	 }
+         /* move focus around the dialog */
+         player->res |= move_focus(player->dialog, cascii, cscan, &player->focus_obj);
       }
-
-      /* broadcast in case any other objects want it */
-      for (c=0; player->dialog[c].proc; c++) {
-	 if (!(player->dialog[c].flags & (D_HIDDEN | D_DISABLED))) {
-	    MESSAGE(c, MSG_XCHAR, ccombo);
-	    if (player->res & D_USED_CHAR)
-	       goto getout;
-	 }
-      }
-
-      /* pass <CR> or <SPACE> to selected object */
-      if (((cascii == '\r') || (cascii == '\n') || (cascii == ' ')) && 
-	  (player->focus_obj >= 0)) {
-	 MESSAGE(player->focus_obj, MSG_KEY, ccombo);
-	 goto getout;
-      }
-
-      /* ESC closes dialog */
-      if (cascii == 27) {
-	 player->res |= D_CLOSE;
-	 player->obj = -1;
-	 goto getout;
-      }
-
-      /* move focus around the dialog */
-      player->res |= move_focus(player->dialog, cascii, cscan, &player->focus_obj);
    }
 
    /* redraw? */

