Let users drag DialogBoxes off the screen in any direction, but only as long as
the mouse pointer stays in the window -- so you can't totally lose a DialogBox.

patch by: ajr
review by: rdayal
suggested by: jgw


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3724 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/DialogBox.java b/user/src/com/google/gwt/user/client/ui/DialogBox.java
index a287962..d52a649 100644
--- a/user/src/com/google/gwt/user/client/ui/DialogBox.java
+++ b/user/src/com/google/gwt/user/client/ui/DialogBox.java
@@ -15,9 +15,12 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.dom.client.Document;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.WindowResizeListener;
 
 /**
  * A form of popup that has a caption area at the top and can be dragged by the
@@ -69,6 +72,10 @@
   private boolean dragging;
   private int dragStartX, dragStartY;
   private MouseListenerCollection mouseListeners = new MouseListenerCollection();
+  private WindowResizeListener resizeListener;
+  private int windowWidth;
+  private int clientLeft;
+  private int clientTop;
 
   /**
    * Creates an empty dialog box. It should not be shown until its child widget
@@ -114,6 +121,10 @@
     // Set the style name
     setStyleName(DEFAULT_STYLENAME);
     sinkEvents(Event.MOUSEEVENTS);
+
+    windowWidth = Window.getClientWidth();
+    clientLeft = Document.get().getBodyOffsetLeft();
+    clientTop = Document.get().getBodyOffsetTop();
   }
 
   public String getHTML() {
@@ -125,6 +136,12 @@
   }
 
   @Override
+  public void hide() {
+    Window.removeWindowResizeListener(resizeListener);
+    super.hide();
+  }
+
+  @Override
   public void onBrowserEvent(Event event) {
     super.onBrowserEvent(event);
 
@@ -178,6 +195,14 @@
     if (dragging) {
       int absX = x + getAbsoluteLeft();
       int absY = y + getAbsoluteTop();
+
+      // if the mouse is off the screen to the left, right, or top, don't
+      // move the dialog box. This would let users lose dialog boxes, which
+      // would be bad for modal popups.
+      if (absX < clientLeft || absX >= windowWidth || absY < clientTop) {
+        return;
+      }
+
       setPopupPosition(absX - dragStartX, absY - dragStartY);
     }
   }
@@ -212,6 +237,19 @@
   }
 
   @Override
+  public void show() {
+    if (resizeListener == null) {
+      resizeListener = new WindowResizeListener() {
+        public void onWindowResized(int width, int height) {
+          windowWidth = width;
+        }
+      };
+    }
+    Window.addWindowResizeListener(resizeListener);
+    super.show();
+  }
+
+  @Override
   protected void doAttachChildren() {
     super.doAttachChildren();
 
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index ab2450a..e7f63d4 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -573,17 +573,6 @@
    * @param top the top position, in pixels
    */
   public void setPopupPosition(int left, int top) {
-    // Keep the popup within the browser's client area, so that they can't get
-    // 'lost' and become impossible to interact with. Note that we don't attempt
-    // to keep popups pegged to the bottom and right edges, as they will then
-    // cause scrollbars to appear, so the user can't lose them.
-    if (left < 0) {
-      left = 0;
-    }
-    if (top < 0) {
-      top = 0;
-    }
-
     // Save the position of the popup
     leftPosition = left;
     topPosition = top;