Index: PerspectiveHelper.java =================================================================== RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/PerspectiveHelper.java,v retrieving revision 1.11 diff -u -r1.11 PerspectiveHelper.java --- PerspectiveHelper.java 27 Aug 2004 04:11:33 -0000 1.11 +++ PerspectiveHelper.java 2 Sep 2004 18:46:43 -0000 @@ -14,10 +14,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.util.Geometry; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Cursor; @@ -25,6 +29,9 @@ import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Monitor; +import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewReference; import org.eclipse.ui.IWorkbenchPartReference; @@ -116,10 +123,18 @@ private LayoutPart part; private Rectangle dragRectangle; + + private Window window; + + private int MAXIMUM_SNAP_DISTANCE = 40; + + private List distances = new ArrayList(5); + private Map distancesToPoints = new HashMap(5); + private Map pointsToRectangles = new HashMap(5); private ActualDropTarget(LayoutPart part, Rectangle dragRectangle) { super(); - setTarget(part, dragRectangle); + setTarget(part, dragRectangle); } /** @@ -129,12 +144,11 @@ */ private void setTarget(LayoutPart part, Rectangle dragRectangle) { this.part = part; - this.dragRectangle = dragRectangle; + this.dragRectangle = dragRectangle; + this.window = part.getWindow(); } public void drop() { - - Window window = part.getWindow(); if (window instanceof DetachedWindow) { // only one tab folder in a detach window, so do window // move @@ -164,6 +178,199 @@ public Cursor getCursor() { return DragCursors.getCursor(DragCursors.OFFSCREEN); } + + public Rectangle getSnapRectangle() { + Rectangle snapRect = null; + Point initial = window.getShell().getDisplay().getCursorLocation(); + Rectangle sourceRect = dragRectangle; + + Rectangle offScreen = null; + + if(window instanceof WorkbenchWindow) { + ILayoutContainer cont = part.getContainer(); + if(cont != null && cont instanceof PartStack) + Geometry.setSize(sourceRect, ((PartStack)part.getContainer()).getSize()); + else + Geometry.setSize(sourceRect, part.getControl().getSize()); + } + else { + Geometry.setSize(sourceRect, window.getShell().getSize()); + } + + int[] sides = { SWT.TOP, SWT.BOTTOM, SWT.RIGHT, SWT.LEFT }; + + + for (int i = 0; i < sides.length; i++) { + getEdges(sourceRect, sides[i]); + Collections.sort(distances); + for (Iterator iter = distances.iterator(); iter.hasNext();) { + Point found = (Point)distancesToPoints.get((Double) iter.next()); + if(found != null) { + boolean finished = false; + switch (sides[i]) { + case SWT.TOP: + if((found.y + MAXIMUM_SNAP_DISTANCE) > initial.y && + (found.y) < initial.y) { + offScreen = sourceRect; + offScreen.y = found.y; + if(willBeTouching(offScreen, found, SWT.BOTTOM)) { + snapRect = offScreen; + finished = true; + } + } + else if((found.y) > initial.y && + (found.y- MAXIMUM_SNAP_DISTANCE) < initial.y) { + offScreen = sourceRect; + offScreen.y = (found.y - sourceRect.height); + if(willBeTouching(offScreen, found, SWT.BOTTOM)) { + snapRect = offScreen; + finished = true; + } + } + break; + case SWT.BOTTOM: + if((found.y + MAXIMUM_SNAP_DISTANCE) > initial.y && + (found.y) < initial.y) { + offScreen = sourceRect; + offScreen.y = found.y; + if(willBeTouching(offScreen, found, SWT.TOP)) { + snapRect = offScreen; + finished = true; + } + } + else if((found.y) > initial.y && + (found.y - MAXIMUM_SNAP_DISTANCE) < initial.y) { + offScreen = sourceRect; + offScreen.y = (found.y - sourceRect.height); + if(willBeTouching(offScreen, found, SWT.TOP)) { + snapRect = offScreen; + finished = true; + } + } + break; + case SWT.RIGHT: + if((found.x + MAXIMUM_SNAP_DISTANCE) > initial.x && + (found.x) < initial.x) { + offScreen = sourceRect; + offScreen.x = found.x; + if(willBeTouching(offScreen, found, SWT.LEFT)) { + snapRect = offScreen; + finished = true; + } + } + else if((found.x) > initial.x && + (found.x - MAXIMUM_SNAP_DISTANCE) < initial.x) { + offScreen = sourceRect; + offScreen.x = (found.x - sourceRect.width); + if(willBeTouching(offScreen, found, SWT.LEFT)) { + snapRect = offScreen; + finished = true; + } + } + break; + case SWT.LEFT: + if((found.x + MAXIMUM_SNAP_DISTANCE) > initial.x && + (found.x) < initial.x) { + offScreen = sourceRect; + offScreen.x = found.x; + if(willBeTouching(offScreen, found, SWT.RIGHT)) { + snapRect = offScreen; + finished = true; + } + } + if((found.x > initial.x) && + (found.x - MAXIMUM_SNAP_DISTANCE) < initial.x) { + offScreen = sourceRect; + offScreen.x = (found.x - sourceRect.width); + if(willBeTouching(offScreen, found, SWT.RIGHT)) { + snapRect = offScreen; + finished = true; + } + } + break; + } + if(finished) { + break; + } + } + } + } + return snapRect; + } + + private void getEdges(Rectangle source, int side) { + Shell shell = window.getShell(); + Point closest = null; + distances.clear(); + distancesToPoints.clear(); + pointsToRectangles.clear(); + Rectangle clientArea; + if (shell != null) { + Point sourceSide = createCenterPoint(source, side); + Vector pointsToSearch = new Vector(11); + + // first we check the edges of monitors + Display display = shell.getDisplay(); + Monitor[] monitors = display.getMonitors(); + + for (int idx = 0; idx < monitors.length; idx++) { + Monitor mon = monitors[idx]; + clientArea = mon.getClientArea(); + Point p = createCenterPoint(clientArea, side); + pointsToSearch.add(p); + pointsToRectangles.put(p, clientArea); + } + + // now search the shells + // shells that do not have the data field set do not have a window + // associated with them, therefore we do not search them + + // we also don't search for the shell we're moving + Shell[] shells = display.getShells(); + for (int i = 0; i < shells.length; i++) { + if(shells[i].getData() != null) { + if(shells[i] == shell && !(shells[i].getData() instanceof WorkbenchWindow)) { + continue; + } + clientArea = shells[i].getBounds(); + Point p = createCenterPoint(clientArea, side); + pointsToSearch.add(p); + pointsToRectangles.put(p, clientArea); + } + } + + // real work + for (Iterator iter = pointsToSearch.iterator(); iter.hasNext();) { + Point toSearch = (Point) iter.next(); + double dSquared = Geometry.distanceSquared(sourceSide, toSearch); + distances.add(new Double(dSquared)); + distancesToPoints.put(new Double(dSquared), toSearch); + + } + } + + } + + private boolean willBeTouching(Rectangle toTest, Point p, int side) { + Rectangle source = (Rectangle)pointsToRectangles.get(p); + Geometry.expand(source, 15, 15, 15, 15); + return source.intersects(toTest); + } + + private Point createCenterPoint(Rectangle toSearch, int side) { + switch (side){ + case SWT.TOP: + return new Point((int)((double)toSearch.width/(double)2) + toSearch.x, toSearch.y); + case SWT.BOTTOM: + return new Point((int)((double)toSearch.width/(double)2) + toSearch.x, toSearch.height + toSearch.y); + case SWT.LEFT: + return new Point(toSearch.x, (int)((double)toSearch.height/(double)2) + toSearch.y); + case SWT.RIGHT: + return new Point(toSearch.width + toSearch.x, (int)((double)toSearch.height/(double)2) + toSearch.y); + } + return new Point(0, 0); + } + } private class MatchingPart implements Comparable {