Skip to content

Commit

Permalink
Ignore space of shadow when aligning tooltip border
Browse files Browse the repository at this point in the history
Relates to #298
  • Loading branch information
weisJ committed Jan 6, 2022
1 parent ff44d37 commit 2ef0cb7
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -24,6 +24,8 @@

import javax.swing.*;

import org.jetbrains.annotations.NotNull;

import com.github.weisj.darklaf.util.Alignment;

public interface AlignableTooltipBorder {
Expand All @@ -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);
}
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;

Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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();

Expand All @@ -72,15 +68,18 @@ private static Point getBestPositionMatch(final ToolTipContext context, final Po

Alignment[] alignments = getAlignments(targetAlignment);
Point pos;
BiConsumer<ToolTipContext, Alignment> setter =
isCenter ? ToolTipContext::setCenterAlignment : ToolTipContext::setAlignment;
BiConsumer<ToolTipContext, Alignment> 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);
}

/*
Expand All @@ -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<ToolTipContext, Alignment> setter, final boolean centerHorizontally,
final boolean centerVertically) {
final LayoutConstraints layoutConstraints, final BiConsumer<ToolTipContext, Alignment> 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;
Expand All @@ -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<ToolTipContext, Alignment> setter, final boolean centerHorizontally,
final boolean centerVertically) {
setter.accept(context, a);
Expand All @@ -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) {
Expand All @@ -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);
}
}
}

0 comments on commit 2ef0cb7

Please sign in to comment.