overlay: fix layouted overlays not respecting parent bounds

This clamps layouted overlays to their parent's bounds, and also adjusts
the snap corner for the shifted position that is a result of the clamp,
so that the following overlays correctly get layouted.
This commit is contained in:
Adam
2021-01-06 17:39:14 -05:00
parent 86940e139b
commit ae18d2a865
2 changed files with 33 additions and 25 deletions

View File

@@ -266,29 +266,35 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
else
{
final Rectangle bounds = overlay.getBounds();
final Point location = bounds.getLocation();
final Dimension dimension = bounds.getSize();
final Point preferredLocation = overlay.getPreferredLocation();
Point location;
// If the final position is not modified, layout it
if (overlayPosition != OverlayPosition.DETACHED && (preferredLocation == null || overlay.getPreferredPosition() != null))
{
final Rectangle snapCorner = snapCorners.forPosition(overlayPosition);
final Point translation = OverlayUtil.transformPosition(overlayPosition, dimension);
location.setLocation(snapCorner.getX() + translation.x, snapCorner.getY() + translation.y);
final Point padding = OverlayUtil.padPosition(overlayPosition, dimension, PADDING);
snapCorner.translate(padding.x, padding.y);
final Point translation = OverlayUtil.transformPosition(overlayPosition, dimension); // offset from corner
// Target x/y to draw the overlay
int destX = (int) snapCorner.getX() + translation.x;
int destY = (int) snapCorner.getY() + translation.y;
// Clamp the target position to ensure it is on screen or within parent bounds
location = clampOverlayLocation(destX, destY, dimension.width, dimension.height, overlay);
// Diff final position to target position in order to add it to the snap corner padding. The
// overlay effectively takes up the difference of (clamped location - target location) in
// addition to its normal dimensions.
int dX = location.x - destX;
int dY = location.y - destY;
final Point padding = OverlayUtil.padPosition(overlayPosition, dimension, PADDING); // overlay size + fixed padding
// translate corner for padding and any difference due to the position clamping
snapCorner.translate(padding.x + dX, padding.y + dY);
}
else
{
if (preferredLocation != null)
{
location.setLocation(preferredLocation);
}
location = preferredLocation != null ? preferredLocation : bounds.getLocation();
// Clamp the overlay position to ensure it is on screen or within parent bounds
clampOverlayLocation(location, dimension.width, dimension.height, overlay);
location = clampOverlayLocation(location.x, location.y, dimension.width, dimension.height, overlay);
}
if (overlay.getPreferredSize() != null)
@@ -605,7 +611,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
// Clamp drag to parent component
final Rectangle overlayBounds = currentManagedOverlay.getBounds();
clampOverlayLocation(overlayPosition, overlayBounds.width, overlayBounds.height, currentManagedOverlay);
overlayPosition = clampOverlayLocation(overlayPosition.x, overlayPosition.y, overlayBounds.width, overlayBounds.height, currentManagedOverlay);
currentManagedOverlay.setPreferredPosition(null);
currentManagedOverlay.setPreferredLocation(overlayPosition);
}
@@ -920,12 +926,14 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
/**
* Adjust the given overlay position to be within its parent's bounds.
*
* @param overlayPosition the overlay position, which is modified in place
* @param overlayX
* @param overlayY
* @param overlayWidth
* @param overlayHeight
* @param overlay the overlay
* @param overlay the overlay
* @return the clamped position
*/
private void clampOverlayLocation(Point overlayPosition, int overlayWidth, int overlayHeight, Overlay overlay)
private Point clampOverlayLocation(int overlayX, int overlayY, int overlayWidth, int overlayHeight, Overlay overlay)
{
Rectangle parentBounds = overlay.getParentBounds();
if (parentBounds == null || parentBounds.isEmpty())
@@ -936,9 +944,11 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
}
// Constrain overlay position to be within the parent bounds
overlayPosition.x = Ints.constrainToRange(overlayPosition.x, parentBounds.x,
Math.max(parentBounds.x, parentBounds.width - overlayWidth));
overlayPosition.y = Ints.constrainToRange(overlayPosition.y, parentBounds.y,
Math.max(parentBounds.y, parentBounds.height - overlayHeight));
return new Point(
Ints.constrainToRange(overlayX, parentBounds.x,
Math.max(parentBounds.x, parentBounds.width - overlayWidth)),
Ints.constrainToRange(overlayY, parentBounds.y,
Math.max(parentBounds.y, parentBounds.height - overlayHeight))
);
}
}

View File

@@ -217,8 +217,6 @@ public class OverlayUtil
break;
case TOP_LEFT:
case TOP_CENTER:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
break;
case CANVAS_TOP_RIGHT:
case TOP_RIGHT:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
@@ -242,18 +240,18 @@ public class OverlayUtil
case TOP_LEFT:
break;
case TOP_CENTER:
result.x = result.x - dimension.width / 2;
result.x = -dimension.width / 2;
break;
case BOTTOM_LEFT:
result.y = result.y - dimension.height;
result.y = -dimension.height;
break;
case BOTTOM_RIGHT:
case ABOVE_CHATBOX_RIGHT:
result.y = result.y - dimension.height;
result.y = -dimension.height;
// FALLTHROUGH
case CANVAS_TOP_RIGHT:
case TOP_RIGHT:
result.x = result.x - dimension.width;
result.x = -dimension.width;
break;
}