package com.mkalugin.corchy.internal.ui.location;
import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Monitor;
public enum ShellPositionConstraint {
INTERSECTS_ANY_MONITOR {
@Override
public Rectangle constrain(Rectangle preferredDimensions, Display display) {
if (intersectsAnyMonitor(preferredDimensions, display))
return preferredDimensions;
else
return constrainToSingleMonitor(preferredDimensions, display);
}
},
CONTAINED_WITHIN_SINGLE_MONITOR {
@Override
public Rectangle constrain(Rectangle preferredDimensions, Display display) {
return constrainToSingleMonitor(preferredDimensions, display);
}
};
public abstract Rectangle constrain(Rectangle preferredDimensions, Display display);
private static Rectangle constrainToSingleMonitor(Rectangle preferredDimensions, Display display) {
Rectangle result = new Rectangle(preferredDimensions.x, preferredDimensions.y,
preferredDimensions.width, preferredDimensions.height);
Monitor mon = getClosestMonitor(display, Geometry.centerPoint(result));
Rectangle bounds = mon.getClientArea();
if (result.height > bounds.height) {
result.height = bounds.height;
}
if (result.width > bounds.width) {
result.width = bounds.width;
}
result.x = Math.max(bounds.x, Math.min(result.x, bounds.x + bounds.width - result.width));
result.y = Math.max(bounds.y, Math.min(result.y, bounds.y + bounds.height - result.height));
return result;
}
/**
* Returns the monitor whose client area contains the given point. If no
* monitor contains the point, returns the monitor that is closest to the
* point. If this is ever made public, it should be moved into a separate
* utility class.
*
* @param toSearch
* point to find (display coordinates)
* @param toFind
* point to find (display coordinates)
* @return the montor closest to the given point
*/
private static Monitor getClosestMonitor(Display toSearch, Point toFind) {
int closest = Integer.MAX_VALUE;
Monitor[] monitors = toSearch.getMonitors();
Monitor result = monitors[0];
for (int idx = 0; idx < monitors.length; idx++) {
Monitor current = monitors[idx];
Rectangle clientArea = current.getClientArea();
if (clientArea.contains(toFind)) {
return current;
}
int distance = Geometry.distanceSquared(Geometry.centerPoint(clientArea), toFind);
if (distance < closest) {
closest = distance;
result = current;
}
}
return result;
}
/**
*
* Returns true iff the given rectangle is located in the client area of any
* monitor.
*
* @param someRectangle
* a rectangle in display coordinates (not null)
* @return true iff the given point can be seen on any monitor
*/
public static boolean intersectsAnyMonitor(Rectangle someRectangle, Display display) {
Monitor[] monitors = display.getMonitors();
for (int idx = 0; idx < monitors.length; idx++) {
Monitor mon = monitors[idx];
if (mon.getClientArea().intersects(someRectangle)) {
return true;
}
}
return false;
}
}