diff --git a/platform/platform-api/src/com/intellij/openapi/ui/popup/Balloon.java b/platform/platform-api/src/com/intellij/openapi/ui/popup/Balloon.java index 555766e1a0dd..872da477975b 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/popup/Balloon.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/popup/Balloon.java @@ -38,6 +38,9 @@ public interface Balloon extends Disposable { void hide(); + boolean wasFadedIn(); + boolean wasFadedOut(); + enum Position { below, above, atLeft, atRight } diff --git a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java index f275e2a428b5..e8e95ea9b8e1 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java @@ -51,6 +51,7 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener private int myX; private int myY; + private RegistryValue myMode; @NotNull @Override @@ -64,6 +65,8 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener @Override public void initComponent() { + myMode = Registry.get("ide.tooltip.mode"); + myIsEnabled = Registry.get("ide.tooltip.callout"); myIsEnabled.addListener(new RegistryValueListener.Adapter() { @Override @@ -97,8 +100,18 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener } } else if (me.getID() == MouseEvent.MOUSE_MOVED) { if (me.getComponent() == myCurrentComponent) { - myX = me.getX(); - myY = me.getY(); + if (myCurrentTip != null && myCurrentTip.wasFadedIn()) { + hideCurrent(); + } else { + myX = me.getX(); + myY = me.getY(); + } + } else if (myCurrentComponent == null) { + maybeShowFor(c, me); + } + } else if (me.getID() == MouseEvent.MOUSE_PRESSED) { + if (me.getComponent() == myCurrentComponent) { + hideCurrent(); } } } @@ -130,7 +143,7 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener public void run() { show(c, e, tooltipText, toCenter); } - }, myShowDelay ? 750 : 250); + }, myShowDelay ? 1500 : 900); } private void show(Component c, MouseEvent e, String tooltipText, boolean toCenter) { @@ -138,15 +151,30 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener myTipLabel.setText(tooltipText); - Color bg = new Color(100, 100, 100, 230); + boolean useSystem; + + if ("default".equalsIgnoreCase(myMode.asString())) { + useSystem = false; + } else if ("system".equalsIgnoreCase(myMode.asString())) { + useSystem = true; + } else if ("graphite".equalsIgnoreCase(myMode.asString())) { + useSystem = false; + } else { + useSystem = false; + } + + Color bg = useSystem ? UIManager.getColor("ToolTip.background") : new Color(100, 100, 100, 230); + Color fg = useSystem ? UIManager.getColor("ToolTip.foreground") : Color.white; + Color border = useSystem ? Color.darkGray : bg; + BalloonBuilder builder = myPopupFactory.createBalloonBuilder(myTipLabel) .setPreferredPosition(Balloon.Position.above) .setFillColor(bg) - .setBorderColor(bg) + .setBorderColor(border) .setAnimationCycle(150) .setShowCallout(true); - myTipLabel.setForeground(Color.white); - myTipLabel.setBorder(new EmptyBorder(0, 2, 0, 2)); + myTipLabel.setForeground(fg); + myTipLabel.setBorder(new EmptyBorder(1, 3, 2, 3)); Font font = UIManager.getFont("Label.font"); myTipLabel.setFont(font.deriveFont(Font.PLAIN, font.getSize() - 2)); myCurrentTip = builder.createBalloon(); @@ -168,7 +196,7 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener if (toCenter) { Rectangle bounds = e.getComponent().getBounds(); point.x = toCenterX ? bounds.width / 2 : point.x; - point.y = toCenterY ? (bounds.height / 2 - (bounds.height / 5)) : point.y; + point.y = toCenterY ? (bounds.height / 2) : point.y; } myCurrentTip.show(new RelativePoint(c, point), Balloon.Position.above); diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index f803b390a926..a29037b42655 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -29,19 +29,22 @@ import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.Alarm; +import com.intellij.util.IJSwingUtilities; import com.intellij.util.Range; +import com.intellij.util.containers.HashSet; import com.intellij.util.ui.*; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; -import javax.swing.text.html.HTMLEditorKit; import java.awt.*; import java.awt.event.*; import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; +import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; public class BalloonImpl implements Disposable, Balloon, LightweightWindow, PositionTracker.Client { @@ -55,7 +58,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi private final Color myBorderColor; private final Color myFillColor; - private final Insets myContainerInsets = new Insets(4, 4, 4, 4); + private final Insets myContainerInsets = new Insets(2, 2, 2, 2); private boolean myLastMoveWasInsideBalloon; @@ -119,6 +122,9 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi private PositionTracker myTracker; private int myAnimationCycle = 500; + private boolean myFadedIn; + private boolean myFadedOut; + private boolean isInsideBalloon(MouseEvent me) { if (!me.getComponent().isShowing()) return true; if (SwingUtilities.isDescendingFrom(me.getComponent(), myComp) || me.getComponent() == myComp) return true; @@ -232,17 +238,17 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi myTracker = tracker; myTracker.init(this); - final Window window = SwingUtilities.getWindowAncestor(tracker.getComponent()); - JRootPane root = null; - if (window instanceof JFrame) { - root = ((JFrame)window).getRootPane(); - } - else if (window instanceof JDialog) { - root = ((JDialog)window).getRootPane(); - } - else { - assert false : window; + JDialog dialog = IJSwingUtilities.findParentOfType(tracker.getComponent(), JDialog.class); + if (dialog != null) { + root = dialog.getRootPane(); + } else { + JFrame frame = IJSwingUtilities.findParentOfType(tracker.getComponent(), JFrame.class); + if (frame != null) { + root = frame.getRootPane(); + } else { + assert false; + } } myVisible = true; @@ -252,19 +258,51 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi myLayeredPane.addComponentListener(myComponentListener); + myTargetPoint = myTracker.recalculateLocation(this).getPoint(myLayeredPane); + + + if (myShowPointer) { + Rectangle rec = getRecForPosition(myPosition, true); + + if (!myPosition.isOkToHavePointer(myTargetPoint, rec, getPointerLength(myPosition), getPointerWidth(myPosition), getArc(), getNormalInset())) { + rec = getRecForPosition(myPosition, false); + + Rectangle lp = new Rectangle(new Point(myContainerInsets.left, myContainerInsets.top), myLayeredPane.getSize()); + lp.width -= myContainerInsets.right; + lp.height -= myContainerInsets.bottom; + + if (!lp.contains(rec)) { + Rectangle2D currentSquare = lp.createIntersection(rec); + + double maxSquare = currentSquare.getWidth() * currentSquare.getHeight(); + Position targetPosition = myPosition; + + for (Position eachPosition : myPosition.getOtherPositions()) { + Rectangle2D eachIntersection = lp.createIntersection(getRecForPosition(eachPosition, false)); + double eachSquare = eachIntersection.getWidth() * eachIntersection.getHeight(); + if (maxSquare < eachSquare) { + maxSquare = eachSquare; + targetPosition = eachPosition; + } + } + + myPosition = targetPosition; + } + } + } + createComponent(); myComp.validate(); - Rectangle compBounds = myComp.getBounds(); - Rectangle contentRec = SwingUtilities.convertRectangle(myContent.getParent(), myContent.getBounds(), myLayeredPane); + Rectangle rec = myComp.getBounds(); - if (myShowPointer && !myPosition.isOkToHavePointer(myTargetPoint, contentRec, this)) { + if (myShowPointer && !myPosition.isOkToHavePointer(myTargetPoint, rec, getPointerLength(myPosition), getPointerWidth(myPosition), getArc(), getNormalInset())) { myShowPointer = false; myComp.removeAll(); myLayeredPane.remove(myComp); - myForcedBounds = myPosition.getPointlessContentRec(compBounds, this); + myForcedBounds = rec; createComponent(); } @@ -283,19 +321,46 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi KeyEvent.KEY_EVENT_MASK); } + private Rectangle getRecForPosition(Position position, boolean adjust) { + Dimension size = getContentSizeFor(position); + + Rectangle rec = new Rectangle(new Point(0, 0), size); + + position.setRecToRelativePosition(rec, myTargetPoint); + + if (adjust) { + rec = myPosition + .getUpdatedBounds(myLayeredPane.getSize(), myForcedBounds, rec.getSize(), myShowPointer, myTargetPoint, myContainerInsets); + } + + return rec; + } + + private Dimension getContentSizeFor(Position position) { + Insets insets = position.createBorder(this).getBorderInsets(); + if (insets == null) { + insets = new Insets(0, 0, 0, 0); + } + + Dimension size = myContent.getPreferredSize(); + size.width += insets.left + insets.right; + size.height += insets.top + insets.bottom; + + return size; + } + private void createComponent() { myComp = new MyComponent(myContent, this, myShowPointer ? myPosition.createBorder(this) : getPointlessBorder()); - myTargetPoint = myTracker.recalculateLocation(this).getPoint(myLayeredPane); myComp.clear(); myComp.myAlpha = 0f; myLayeredPane.add(myComp, JLayeredPane.POPUP_LAYER); - myPosition.updateLocation(this); + myPosition.updateBounds(this); } @@ -308,7 +373,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi if (newPosition != null) { myTargetPoint = newPosition.getPoint(myLayeredPane); - myPosition.updateLocation(this); + myPosition.updateBounds(this); } } @@ -342,6 +407,8 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi myComp.clear(); myComp.repaint(); + myFadedIn = true; + startFadeoutTimer(); } else { @@ -376,23 +443,19 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi int getArc() { - return 6; + return 3; } - int getPointerWidth() { - return 12; + int getPointerWidth(Position position) { + return position.isTopBottomPointer() ? 14 : 11; } int getNormalInset() { - return 4; + return 3; } - int getShadowShift() { - return 10; - } - - int getPointerLength() { - return 12; + int getPointerLength(Position position) { + return position.isTopBottomPointer() ? 10 : 8; } public void hide() { @@ -402,6 +465,8 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi for (JBPopupListener each : myListeners) { each.onClosed(new LightweightWindowEvent(this)); } + + myFadedOut = true; } public void addListener(JBPopupListener listener) { @@ -447,7 +512,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi public void setBounds(Rectangle bounds) { myForcedBounds = bounds; if (myPosition != null) { - myPosition.updateLocation(this); + myPosition.updateBounds(this); } } @@ -469,22 +534,36 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi abstract EmptyBorder createBorder(final BalloonImpl balloon); - public void updateLocation(final BalloonImpl balloon) { - Rectangle bounds = balloon.myForcedBounds; + abstract void setRecToRelativePosition(Rectangle rec, Point targetPoint); + + + public void updateBounds(final BalloonImpl balloon) { + balloon.myComp._setBounds(getUpdatedBounds(balloon.myLayeredPane.getSize(), + balloon.myForcedBounds, + balloon.myComp.getPreferredSize(), + balloon.myShowPointer, + balloon.myTargetPoint, + balloon.myContainerInsets)); + } + + public Rectangle getUpdatedBounds(Dimension layeredPaneSize, + Rectangle forcedBounds, + Dimension preferredSize, + boolean showPointer, + Point targetPoint, Insets containerInsets) { + + Rectangle bounds = forcedBounds; if (bounds == null) { - final Dimension size = balloon.myComp.getPreferredSize(); - balloon.myComp.setSize(size); - final Dimension layeredPaneSize = balloon.myLayeredPane.getSize(); - Point location = balloon.myShowPointer - ? getLocation(layeredPaneSize, balloon.myTargetPoint, size) - : new Point(balloon.myTargetPoint.x - size.width / 2, balloon.myTargetPoint.y - size.height / 2); - bounds = new Rectangle(location.x, location.y, size.width, size.height); + Point location = showPointer + ? getLocation(layeredPaneSize, targetPoint, preferredSize) + : new Point(targetPoint.x - preferredSize.width / 2, targetPoint.y - preferredSize.height / 2); + bounds = new Rectangle(location.x, location.y, preferredSize.width, preferredSize.height); - ScreenUtil.moveToFit(bounds, new Rectangle(0, 0, layeredPaneSize.width, layeredPaneSize.height), balloon.myContainerInsets); + ScreenUtil.moveToFit(bounds, new Rectangle(0, 0, layeredPaneSize.width, layeredPaneSize.height), containerInsets); } - balloon.myComp._setBounds(bounds); + return bounds; } abstract Point getLocation(final Dimension containerSize, final Point targetPoint, final Dimension balloonSize); @@ -513,31 +592,21 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi final Point pointTarget, final BalloonImpl balloon); - public boolean isOkToHavePointer(Point targetPoint, Rectangle bounds, BalloonImpl balloon) { - if (bounds.contains(targetPoint)) { - return false; - } + public boolean isOkToHavePointer(Point targetPoint, Rectangle bounds, int pointerLength, int pointerWidth, int arc, int normalInset) { + if (bounds.x < targetPoint.x && bounds.x + bounds.width > targetPoint.x && bounds.y < targetPoint.y && bounds.y + bounds.height < targetPoint.y) return false; - Rectangle pointless = getPointlessContentRec(bounds, balloon); + Rectangle pointless = getPointlessContentRec(bounds, pointerLength); - pointless.x += (balloon.getArc() + 1); - pointless.width -= (balloon.getArc() * 2 + 2); - pointless.y += (balloon.getArc() + 1); - pointless.height -= (balloon.getArc() * 2 + 2); - - - int size = getDistanceToTarget(bounds, targetPoint); - if (size < balloon.getPointerLength() + balloon.getNormalInset()) return false; - - int pointerWidth = balloon.getPointerWidth(); + int size = getDistanceToTarget(pointless, targetPoint); + if (size < pointerLength) return false; Range balloonRange; Range pointerRange; if (isTopBottomPointer()) { - balloonRange = new Range(bounds.x, bounds.x + bounds.width); + balloonRange = new Range(bounds.x + arc, bounds.x + bounds.width - arc * 2); pointerRange = new Range(targetPoint.x - pointerWidth / 2, targetPoint.x + pointerWidth / 2); } else { - balloonRange = new Range(bounds.y, bounds.y + bounds.height); + balloonRange = new Range(bounds.y + arc, bounds.y + bounds.height - arc * 2); pointerRange = new Range(targetPoint.y - pointerWidth / 2, targetPoint.y + pointerWidth / 2); } @@ -550,8 +619,19 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi return this instanceof Below || this instanceof Above; } - protected abstract Rectangle getPointlessContentRec(Rectangle bounds, BalloonImpl balloon); + protected abstract Rectangle getPointlessContentRec(Rectangle bounds, int pointerLength); + public Set getOtherPositions() { + HashSet all = new HashSet(); + all.add(BELOW); + all.add(ABOVE); + all.add(AT_RIGHT); + all.add(AT_LEFT); + + all.remove(this); + + return all; + } } public static final Position BELOW = new Below(); @@ -569,12 +649,17 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } @Override - protected Rectangle getPointlessContentRec(Rectangle bounds, BalloonImpl balloon) { - return new Rectangle(bounds.x, bounds.y + balloon.getPointerLength(), bounds.width, bounds.height - balloon.getPointerLength()); + protected Rectangle getPointlessContentRec(Rectangle bounds, int pointerLength) { + return new Rectangle(bounds.x, bounds.y + pointerLength, bounds.width, bounds.height - pointerLength); } EmptyBorder createBorder(final BalloonImpl balloon) { - return new EmptyBorder(balloon.getPointerLength() + balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset()); + return new EmptyBorder(balloon.getPointerLength(this) + balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset()); + } + + @Override + void setRecToRelativePosition(Rectangle rec, Point targetPoint) { + rec.setLocation(new Point(targetPoint.x - rec.width / 2, targetPoint.y)); } Point getLocation(final Dimension containerSize, final Point targetPoint, final Dimension balloonSize) { @@ -583,23 +668,23 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } protected void convertBoundsToContent(final Rectangle bounds, final BalloonImpl balloon) { - bounds.y += balloon.getPointerLength(); - bounds.height -= balloon.getPointerLength() - 1; + bounds.y += balloon.getPointerLength(this); + bounds.height -= balloon.getPointerLength(this) - 1; } protected Shape getPointingShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { final Shaper shaper = new Shaper(balloon, bounds, pointTarget, SwingUtilities.TOP); - shaper.line(balloon.getPointerWidth() / 2, balloon.getPointerLength()).toRightCurve().roundRightDown().toBottomCurve().roundLeftDown() + shaper.line(balloon.getPointerWidth(this) / 2, balloon.getPointerLength(this)).toRightCurve().roundRightDown().toBottomCurve().roundLeftDown() .toLeftCurve().roundLeftUp().toTopCurve().roundUpRight() - .lineTo(pointTarget.x - balloon.getPointerWidth() / 2, shaper.getCurrent().y).lineTo(pointTarget.x, pointTarget.y); + .lineTo(pointTarget.x - balloon.getPointerWidth(this) / 2, shaper.getCurrent().y).lineTo(pointTarget.x, pointTarget.y); shaper.close(); return shaper.getShape(); } protected Shape getShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { - bounds.y += balloon.getPointerLength(); - bounds.height += balloon.getPointerLength(); + bounds.y += balloon.getPointerLength(this); + bounds.height += balloon.getPointerLength(this); return new RoundRectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height, balloon.getArc(), balloon.getArc()); } @@ -613,12 +698,20 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } @Override - protected Rectangle getPointlessContentRec(Rectangle bounds, BalloonImpl balloon) { - return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height - balloon.getPointerLength()); + protected Rectangle getPointlessContentRec(Rectangle bounds, int pointerLength) { + return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height - pointerLength); } EmptyBorder createBorder(final BalloonImpl balloon) { - return new EmptyBorder(balloon.getNormalInset(), balloon.getNormalInset(), balloon.getPointerLength() + balloon.getNormalInset(), balloon.getNormalInset()); + return new EmptyBorder(balloon.getNormalInset(), + balloon.getNormalInset(), + balloon.getPointerLength(this), + balloon.getNormalInset()); + } + + @Override + void setRecToRelativePosition(Rectangle rec, Point targetPoint) { + rec.setLocation(targetPoint.x - rec.width / 2, targetPoint.y - rec.height); } Point getLocation(final Dimension containerSize, final Point targetPoint, final Dimension balloonSize) { @@ -627,21 +720,21 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } protected void convertBoundsToContent(final Rectangle bounds, final BalloonImpl balloon) { - bounds.height -= balloon.getPointerLength() - 1; + bounds.height -= balloon.getPointerLength(this) - 1; } protected Shape getShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { - bounds.y -= balloon.getPointerLength(); - bounds.height -= balloon.getPointerLength(); + bounds.y -= balloon.getPointerLength(this); + bounds.height -= balloon.getPointerLength(this); return new RoundRectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height, balloon.getArc(), balloon.getArc()); } @Override protected Shape getPointingShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { final Shaper shaper = new Shaper(balloon, bounds, pointTarget, SwingUtilities.BOTTOM); - shaper.line(-balloon.getPointerWidth() / 2, -balloon.getPointerLength() + 1); + shaper.line(-balloon.getPointerWidth(this) / 2, -balloon.getPointerLength(this) + 1); shaper.toLeftCurve().roundLeftUp().toTopCurve().roundUpRight().toRightCurve().roundRightDown().toBottomCurve().line(0, 2) - .roundLeftDown().lineTo(pointTarget.x + balloon.getPointerWidth() / 2, shaper.getCurrent().y).lineTo(pointTarget.x, pointTarget.y) + .roundLeftDown().lineTo(pointTarget.x + balloon.getPointerWidth(this) / 2, shaper.getCurrent().y).lineTo(pointTarget.x, pointTarget.y) .close(); @@ -657,12 +750,17 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } @Override - protected Rectangle getPointlessContentRec(Rectangle bounds, BalloonImpl balloon) { - return new Rectangle(bounds.x + balloon.getPointerLength(), bounds.y, bounds.width - balloon.getPointerLength(), bounds.height); + protected Rectangle getPointlessContentRec(Rectangle bounds, int pointerLength) { + return new Rectangle(bounds.x + pointerLength, bounds.y, bounds.width - pointerLength, bounds.height); } EmptyBorder createBorder(final BalloonImpl balloon) { - return new EmptyBorder(balloon.getNormalInset(), balloon.getPointerLength() + balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset()); + return new EmptyBorder(balloon.getNormalInset(), balloon.getPointerLength(this) + balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset()); + } + + @Override + void setRecToRelativePosition(Rectangle rec, Point targetPoint) { + rec.setLocation(targetPoint.x, targetPoint.y - rec.height / 2); } Point getLocation(final Dimension containerSize, final Point targetPoint, final Dimension balloonSize) { @@ -673,21 +771,21 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi @Override protected Shape getPointingShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { final Shaper shaper = new Shaper(balloon, bounds, pointTarget, SwingUtilities.LEFT); - shaper.line(balloon.getPointerLength(), -balloon.getPointerWidth() / 2).toTopCurve().roundUpRight().toRightCurve().roundRightDown() + shaper.line(balloon.getPointerLength(this), -balloon.getPointerWidth(this) / 2).toTopCurve().roundUpRight().toRightCurve().roundRightDown() .toBottomCurve().roundLeftDown().toLeftCurve().roundLeftUp() - .lineTo(shaper.getCurrent().x, pointTarget.y + balloon.getPointerWidth() / 2).lineTo(pointTarget.x, pointTarget.y).close(); + .lineTo(shaper.getCurrent().x, pointTarget.y + balloon.getPointerWidth(this) / 2).lineTo(pointTarget.x, pointTarget.y).close(); return shaper.getShape(); } protected void convertBoundsToContent(final Rectangle bounds, final BalloonImpl balloon) { - bounds.x += balloon.getPointerLength(); - bounds.width -= balloon.getPointerLength(); + bounds.x += balloon.getPointerLength(this); + bounds.width -= balloon.getPointerLength(this); } protected Shape getShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { - bounds.x += balloon.getPointerLength(); - bounds.width -= balloon.getPointerLength(); + bounds.x += balloon.getPointerLength(this); + bounds.width -= balloon.getPointerLength(this); return new RoundRectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height, balloon.getArc(), balloon.getArc()); } } @@ -700,12 +798,17 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } @Override - protected Rectangle getPointlessContentRec(Rectangle bounds, BalloonImpl balloon) { - return new Rectangle(bounds.x, bounds.y, bounds.width - balloon.getPointerLength(), bounds.height); + protected Rectangle getPointlessContentRec(Rectangle bounds, int pointerLength) { + return new Rectangle(bounds.x, bounds.y, bounds.width - pointerLength, bounds.height); } EmptyBorder createBorder(final BalloonImpl balloon) { - return new EmptyBorder(balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset(), balloon.getPointerLength() + balloon.getNormalInset()); + return new EmptyBorder(balloon.getNormalInset(), balloon.getNormalInset(), balloon.getNormalInset(), balloon.getPointerLength(this) + balloon.getNormalInset()); + } + + @Override + void setRecToRelativePosition(Rectangle rec, Point targetPoint) { + rec.setLocation(targetPoint.x - rec.width, targetPoint.y - rec.height / 2); } Point getLocation(final Dimension containerSize, final Point targetPoint, final Dimension balloonSize) { @@ -714,20 +817,20 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } protected void convertBoundsToContent(final Rectangle bounds, final BalloonImpl balloon) { - bounds.width -= balloon.getPointerLength(); + bounds.width -= balloon.getPointerLength(this); } @Override protected Shape getPointingShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { final Shaper shaper = new Shaper(balloon, bounds, pointTarget, SwingUtilities.RIGHT); - shaper.line(-balloon.getPointerLength(), balloon.getPointerWidth() / 2); + shaper.line(-balloon.getPointerLength(this), balloon.getPointerWidth(this) / 2); shaper.toBottomCurve().roundLeftDown().toLeftCurve().roundLeftUp().toTopCurve().roundUpRight().toRightCurve().roundRightDown() - .lineTo(shaper.getCurrent().x, pointTarget.y - balloon.getPointerWidth() / 2).lineTo(pointTarget.x, pointTarget.y).close(); + .lineTo(shaper.getCurrent().x, pointTarget.y - balloon.getPointerWidth(this) / 2).lineTo(pointTarget.x, pointTarget.y).close(); return shaper.getShape(); } protected Shape getShape(final Rectangle bounds, final Graphics2D g, final Point pointTarget, final BalloonImpl balloon) { - bounds.width -= balloon.getPointerLength(); + bounds.width -= balloon.getPointerLength(this); return new RoundRectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height, balloon.getArc(), balloon.getArc()); } } @@ -864,7 +967,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi if (isVisible() && myCloseRec.isVisible()) { Rectangle lpBounds = SwingUtilities.convertRectangle(getParent(), bounds, myLayeredPane); - lpBounds = myPosition.getPointlessContentRec(lpBounds, myBalloon); + lpBounds = myPosition.getPointlessContentRec(lpBounds, myBalloon.getPointerLength(myPosition)); int iconWidth = myBalloon.myCloseButton.getIconWidth(); int iconHeight = myBalloon.myCloseButton.getIconHeight(); @@ -939,7 +1042,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi private int getTargetDelta(int effectiveSide) { - return effectiveSide == myTargetSide ? myBalloon.getPointerLength() : 0; + return effectiveSide == myTargetSide ? myBalloon.getPointerLength(myBalloon.myPosition) : 0; } public Shaper toRightCurve() { @@ -1001,7 +1104,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi pane.setBorder(new LineBorder(Color.blue)); - balloon.set(new BalloonImpl(pane, Color.black, MessageType.ERROR.getPopupBackground(), true, true, true, true, 0, true, null, false, 500)); + balloon.set(new BalloonImpl(pane, Color.black, MessageType.ERROR.getPopupBackground(), true, true, true, false, 0, true, null, false, 500)); balloon.get().setShowPointer(true); if (e.isShiftDown()) { @@ -1020,8 +1123,24 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } }); + tree.addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + System.out.println(e.getPoint()); + } + }); + frame.setBounds(300, 300, 300, 300); frame.show(); } + @Override + public boolean wasFadedIn() { + return myFadedIn; + } + + @Override + public boolean wasFadedOut() { + return myFadedOut; + } } diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 80fa32009718..c67c10f7dd20 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -60,6 +60,8 @@ ide.tree.uiLockAttempt=250 ide.splitter.mouseZone=6 ide.tooltip.callout=true +ide.tooltip.mode=default +ide.tooltip.description=Available options are: default,system,graphite ide.tabbedPane.bufferedPaint=true