IDEA-89532 Value tooltip dissapears before I can click on '+'

This commit is contained in:
Vassiliy Kudryashov
2012-08-07 10:40:17 +04:00
parent 10fa4f95b2
commit 3954e1d1be
3 changed files with 71 additions and 60 deletions
@@ -71,6 +71,7 @@ import com.intellij.psi.search.searches.DefinitionsSearch;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.HintListener;
import com.intellij.ui.LightweightHint;
import com.intellij.ui.ScreenUtil;
import com.intellij.usageView.UsageViewShortNameLocation;
import com.intellij.usageView.UsageViewTypeLocation;
import com.intellij.util.Alarm;
@@ -168,7 +169,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
}
MouseEvent mouseEvent = e.getMouseEvent();
if (isMouseOverTooltip(mouseEvent.getLocationOnScreen()) || isMouseMovedTowardTooltip(mouseEvent.getLocationOnScreen())) {
if (isMouseOverTooltip(mouseEvent.getLocationOnScreen())
|| ScreenUtil.isMovementTowards(myPrevMouseLocation, mouseEvent.getLocationOnScreen(), getHintBounds())) {
myPrevMouseLocation = mouseEvent.getLocationOnScreen();
return;
}
@@ -247,63 +249,6 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
return bounds != null && bounds.contains(mouseLocationOnScreen);
}
private boolean isMouseMovedTowardTooltip(@NotNull Point mouseLocationOnScreen) {
Rectangle bounds = getHintBounds();
if (bounds == null) {
return false;
}
Point prevLocation = myPrevMouseLocation;
if (prevLocation == null) {
myPrevMouseLocation = mouseLocationOnScreen;
return true;
}
else if (prevLocation.equals(mouseLocationOnScreen)) {
return true;
}
int dx = prevLocation.x - mouseLocationOnScreen.x;
int dy = prevLocation.y - mouseLocationOnScreen.y;
// Check if the mouse goes out of the control.
if (dx > 0 && bounds.x >= prevLocation.x) return false;
if (dx < 0 && bounds.x + bounds.width <= prevLocation.x) return false;
if (dy > 0 && bounds.y + bounds.height >= prevLocation.y) return false;
if (dy < 0 && bounds.y <= prevLocation.y) return false;
if (dx == 0) {
return (mouseLocationOnScreen.x >= bounds.x && mouseLocationOnScreen.x < bounds.x + bounds.width)
&& (dy > 0 ^ bounds.y > mouseLocationOnScreen.y);
}
if (dy == 0) {
return (mouseLocationOnScreen.y >= bounds.y && mouseLocationOnScreen.y < bounds.y + bounds.height)
&& (dx > 0 ^ bounds.x > mouseLocationOnScreen.x);
}
// Calculate line equation parameters - y = a * x + b
float a = (float)dy / dx;
float b = mouseLocationOnScreen.y - a * mouseLocationOnScreen.x;
// Check if crossing point with any tooltip border line is within bounds. Don't bother with floating point inaccuracy here.
// Left border.
float crossY = a * bounds.x + b;
if (crossY >= bounds.y && crossY < bounds.y + bounds.height) return true;
// Right border.
crossY = a * (bounds.x + bounds.width) + b;
if (crossY >= bounds.y && crossY < bounds.y + bounds.height) return true;
// Top border.
float crossX = (bounds.y - b) / a;
if (crossX >= bounds.x && crossX < bounds.x + bounds.width) return true;
// Bottom border
crossX = (bounds.y + bounds.height - b) / a;
if (crossX >= bounds.x && crossX < bounds.x + bounds.width) return true;
return false;
}
@Nullable
private Rectangle getHintBounds() {
LightweightHint hint = myHint;
@@ -234,4 +234,62 @@ public class ScreenUtil {
rect.y = (int)screen.getMinY();
}
}
/**
*
* @param prevLocation - previous location on screen
* @param location - current location on screen
* @param bounds - area to check if location shifted towards or not. Also in screen coordinates
* @return true if movement from prevLocation to location is towards specified rectangular area
*/
public static boolean isMovementTowards(final Point prevLocation, final Point location, final Rectangle bounds) {
if (bounds == null) {
return false;
}
if (prevLocation == null || prevLocation.equals(location)) {
return true;
}
int dx = prevLocation.x - location.x;
int dy = prevLocation.y - location.y;
// Check if the mouse goes out of the control.
if (dx > 0 && bounds.x >= prevLocation.x) return false;
if (dx < 0 && bounds.x + bounds.width <= prevLocation.x) return false;
if (dy > 0 && bounds.y + bounds.height >= prevLocation.y) return false;
if (dy < 0 && bounds.y <= prevLocation.y) return false;
if (dx == 0) {
return (location.x >= bounds.x && location.x < bounds.x + bounds.width)
&& (dy > 0 ^ bounds.y > location.y);
}
if (dy == 0) {
return (location.y >= bounds.y && location.y < bounds.y + bounds.height)
&& (dx > 0 ^ bounds.x > location.x);
}
// Calculate line equation parameters - y = a * x + b
float a = (float)dy / dx;
float b = location.y - a * location.x;
// Check if crossing point with any tooltip border line is within bounds. Don't bother with floating point inaccuracy here.
// Left border.
float crossY = a * bounds.x + b;
if (crossY >= bounds.y && crossY < bounds.y + bounds.height) return true;
// Right border.
crossY = a * (bounds.x + bounds.width) + b;
if (crossY >= bounds.y && crossY < bounds.y + bounds.height) return true;
// Top border.
float crossX = (bounds.y - b) / a;
if (crossX >= bounds.x && crossX < bounds.x + bounds.width) return true;
// Bottom border
crossX = (bounds.y + bounds.height - b) / a;
if (crossX >= bounds.x && crossX < bounds.x + bounds.width) return true;
return false;
}
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.keymap.impl.IdeMouseEventDispatcher;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.GraphicsConfig;
import com.intellij.openapi.ui.MessageType;
@@ -164,6 +165,7 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
private boolean myShadow = false;
private Layer myLayer;
private boolean myBlockClicks;
private Point myPrevMousePoint = null;
public boolean isInsideBalloon(MouseEvent me) {
return isInside(new RelativePoint(me));
@@ -177,9 +179,15 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui {
if (cmp == myCloseRec) return true;
if (SwingUtilities.isDescendingFrom(cmp, myComp) || cmp == myComp) return true;
if (myComp == null || !myComp.isShowing()) return false;
if (new Rectangle(myComp.getLocationOnScreen(), myComp.getSize()).contains(target.getScreenPoint())) return true;
Rectangle rectangleOnScreen = new Rectangle(myComp.getLocationOnScreen(), myComp.getSize());
if (rectangleOnScreen.contains(target.getScreenPoint())) return true;
return false;
try {
return ScreenUtil.isMovementTowards(myPrevMousePoint, target.getScreenPoint(), rectangleOnScreen);
}
finally {
myPrevMousePoint = target.getScreenPoint();
}
}
private final ComponentAdapter myComponentListener = new ComponentAdapter() {