mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-89532 Value tooltip dissapears before I can click on '+'
This commit is contained in:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user