diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/AlignableTooltipBorder.java b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/AlignableTooltipBorder.java index ff924de6f..1f9c9cd6b 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/AlignableTooltipBorder.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/AlignableTooltipBorder.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2019-2021 Jannis Weis + * Copyright (c) 2019-2022 Jannis Weis * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, @@ -24,6 +24,8 @@ import javax.swing.*; +import org.jetbrains.annotations.NotNull; + import com.github.weisj.darklaf.util.Alignment; public interface AlignableTooltipBorder { @@ -36,4 +38,7 @@ default Point alignTooltip(final Component c, final Point p, final Alignment ali final boolean outside) { return p; } + + @NotNull + Insets getAlignmentInsets(final JToolTip c); } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkDefaultToolTipBorder.java b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkDefaultToolTipBorder.java index 7807c3d5c..6e044ca11 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkDefaultToolTipBorder.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkDefaultToolTipBorder.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2019-2021 Jannis Weis + * Copyright (c) 2019-2022 Jannis Weis * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, @@ -25,6 +25,8 @@ import javax.swing.*; import javax.swing.plaf.UIResource; +import org.jetbrains.annotations.NotNull; + import com.github.weisj.darklaf.components.border.MutableLineBorder; import com.github.weisj.darklaf.ui.util.DarkUIUtil; @@ -43,4 +45,9 @@ public Insets getBorderInsets(final Component c) { Insets ins = super.getBorderInsets(c); return DarkUIUtil.addInsets(ins, padding); } + + @Override + public @NotNull Insets getAlignmentInsets(final JToolTip c) { + return new Insets(0, 0, 0, 0); + } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipBorder.java b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipBorder.java index bfdc77954..9ace2b877 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipBorder.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/DarkTooltipBorder.java @@ -27,10 +27,13 @@ import javax.swing.*; import javax.swing.border.Border; +import org.jetbrains.annotations.NotNull; + import com.github.weisj.darklaf.components.border.BubbleBorder; import com.github.weisj.darklaf.components.border.DropShadowBorder; import com.github.weisj.darklaf.components.tooltip.ToolTipStyle; import com.github.weisj.darklaf.graphics.PaintUtil; +import com.github.weisj.darklaf.ui.util.DarkUIUtil; import com.github.weisj.darklaf.util.Alignment; import com.github.weisj.darklaf.util.PropertyUtil; import com.github.weisj.darklaf.util.graphics.GraphicsContext; @@ -155,6 +158,12 @@ public Insets getBorderInsets(final Component c) { return ins; } + @Override + public @NotNull Insets getAlignmentInsets(final JToolTip c) { + Insets shadowInsets = shadowBorder.getBorderInsets(c); + return DarkUIUtil.addInsets(shadowInsets, DarkUIUtil.invert(bubbleBorder.getBorderInsets(c))); + } + protected Insets getUserInsets(final Component c) { return PropertyUtil.getObject(c, DarkToolTipUI.KEY_INSETS, Insets.class, margin); } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/ToolTipUtil.java b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/ToolTipUtil.java index 3332e327e..921ca5d6c 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/ToolTipUtil.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tooltip/ToolTipUtil.java @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2020-2021 Jannis Weis + * Copyright (c) 2020-2022 Jannis Weis * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, @@ -25,6 +25,7 @@ import java.util.function.BiConsumer; import javax.swing.*; +import javax.swing.border.Border; import com.github.weisj.darklaf.components.tooltip.ToolTipContext; import com.github.weisj.darklaf.components.tooltip.ToolTipStyle; @@ -56,11 +57,6 @@ private static Point getBestPositionMatch(final ToolTipContext context, final Po if (!context.isBestFit()) { return context.getToolTipLocation(p, null); } - Rectangle screenBounds = DarkUIUtil.getScreenBounds(context.getTarget(), p); - Rectangle windowBounds = DarkUIUtil.getWindow(context.getTarget()).getBounds(); - Rectangle tooltipBounds = new Rectangle(); - tooltipBounds.setSize(context.getToolTip().getPreferredSize()); - Alignment original = context.getAlignment(); Alignment originalCenter = context.getCenterAlignment(); @@ -72,15 +68,18 @@ private static Point getBestPositionMatch(final ToolTipContext context, final Po Alignment[] alignments = getAlignments(targetAlignment); Point pos; - BiConsumer setter = - isCenter ? ToolTipContext::setCenterAlignment : ToolTipContext::setAlignment; + BiConsumer setter = isCenter + ? ToolTipContext::setCenterAlignment + : ToolTipContext::setAlignment; // Check if a position keeps the tooltip inside the window. - pos = tryAlignments(alignments, context, p, tooltipBounds, windowBounds, screenBounds, setter, - centerHorizontally, centerVertically); + + LayoutConstraints layoutConstraints = calculateLayoutConstraints(context, p); + + pos = tryAlignments(alignments, context, p, layoutConstraints, setter, centerHorizontally, centerVertically); if (pos == null) { // Try again with screen bounds instead. - pos = tryAlignments(alignments, context, p, tooltipBounds, screenBounds, screenBounds, setter, - centerHorizontally, centerVertically); + pos = tryAlignments(alignments, context, p, layoutConstraints, setter, centerHorizontally, + centerVertically); } /* @@ -98,18 +97,32 @@ private static Point getBestPositionMatch(final ToolTipContext context, final Po return pos; } + private static LayoutConstraints calculateLayoutConstraints(final ToolTipContext context, final Point p) { + Rectangle screenBounds = DarkUIUtil.getScreenBounds(context.getTarget(), p); + Rectangle windowBounds = DarkUIUtil.getWindow(context.getTarget()).getBounds(); + + JToolTip toolTip = context.getToolTip(); + Rectangle tooltipBounds = new Rectangle(toolTip.getPreferredSize()); + + Border tooltipBorder = toolTip.getBorder(); + Insets layoutInsets = tooltipBorder instanceof AlignableTooltipBorder + ? ((AlignableTooltipBorder) tooltipBorder).getAlignmentInsets(toolTip) + : new Insets(0, 0, 0, 0); + + return new LayoutConstraints(tooltipBounds, windowBounds, screenBounds, layoutInsets); + } + private static Point tryAlignments(final Alignment[] alignments, final ToolTipContext context, final Point p, - final Rectangle tooltipBounds, final Rectangle boundary, final Rectangle screenBoundary, - final BiConsumer setter, final boolean centerHorizontally, - final boolean centerVertically) { + final LayoutConstraints layoutConstraints, final BiConsumer setter, + final boolean centerHorizontally, final boolean centerVertically) { Point pos = null; for (Alignment a : alignments) { if ((centerHorizontally || centerVertically) && a.isDiagonal()) { - pos = tryPosition(a, context, p, tooltipBounds, boundary, screenBoundary, setter, centerHorizontally, + pos = tryPosition(a, context, p, layoutConstraints, setter, centerHorizontally, centerVertically); if (pos != null) break; } - pos = tryPosition(a, context, p, tooltipBounds, boundary, screenBoundary, setter, false, false); + pos = tryPosition(a, context, p, layoutConstraints, setter, false, false); if (pos != null) break; } return pos; @@ -124,7 +137,7 @@ private static Alignment[] getAlignments(final Alignment start) { } private static Point tryPosition(final Alignment a, final ToolTipContext context, final Point p, - final Rectangle tooltipBounds, final Rectangle boundary, final Rectangle screenBoundary, + final LayoutConstraints layoutConstraints, final BiConsumer setter, final boolean centerHorizontally, final boolean centerVertically) { setter.accept(context, a); @@ -133,18 +146,19 @@ private static Point tryPosition(final Alignment a, final ToolTipContext context Point pos = context.getToolTipLocation(p, null, centerHorizontally, centerVertically); Point screenPos = new Point(pos.x, pos.y); SwingUtilities.convertPointToScreen(screenPos, context.getTarget()); - tooltipBounds.setLocation(screenPos); - if (!fits(tooltipBounds, boundary, screenBoundary)) pos = null; + layoutConstraints.tooltipBounds.setLocation(screenPos); + if (!fits(layoutConstraints)) pos = null; return pos; } - private static boolean fits(final Rectangle toolTipBounds, final Rectangle boundary, - final Rectangle screenBoundary) { - if (Objects.equals(boundary, screenBoundary)) { - return SwingUtilities.isRectangleContainingRectangle(boundary, toolTipBounds); + private static boolean fits(final LayoutConstraints layoutConstraints) { + final Rectangle testRectangle = layoutConstraints.testRectangle(); + + if (Objects.equals(layoutConstraints.boundary, layoutConstraints.screenBoundary)) { + return SwingUtilities.isRectangleContainingRectangle(layoutConstraints.boundary, testRectangle); } - return SwingUtilities.isRectangleContainingRectangle(boundary, toolTipBounds) - && SwingUtilities.isRectangleContainingRectangle(screenBoundary, toolTipBounds); + return SwingUtilities.isRectangleContainingRectangle(layoutConstraints.boundary, testRectangle) + && SwingUtilities.isRectangleContainingRectangle(layoutConstraints.screenBoundary, testRectangle); } private static ToolTipContext getToolTipContext(final JToolTip tooltip) { @@ -170,4 +184,25 @@ public static void moveToolTip(final JToolTip toolTip, final int x, final int y, SwingUtilities.convertPointToScreen(p, target); WindowUtil.moveWindow(window, toolTip, p.x, p.y); } + + private static final class LayoutConstraints { + + private final Rectangle tooltipBounds; + private final Rectangle boundary; + private final Rectangle screenBoundary; + private final Insets layoutInsets; + + private LayoutConstraints(final Rectangle tooltipBounds, final Rectangle boundary, + final Rectangle screenBoundary, Insets layoutInsets) { + + this.tooltipBounds = tooltipBounds; + this.boundary = boundary; + this.screenBoundary = screenBoundary; + this.layoutInsets = layoutInsets; + } + + public Rectangle testRectangle() { + return DarkUIUtil.applyInsets(new Rectangle(tooltipBounds), layoutInsets); + } + } }