HoverService
provides the ability to popup data Windows over a Field viewer
@@ -30,7 +29,8 @@ import docking.widgets.fieldpanel.support.FieldLocation;
public interface HoverService {
/**
- * Returns the priority of this hover service.
+ * Returns the priority of this hover service. A lower priority is more important.
+ * @return the priority
*/
public int getPriority();
@@ -41,7 +41,8 @@ public interface HoverService {
public void scroll(int amount);
/**
- * Return whether hover mode is "on."
+ * Return whether hover mode is "on"
+ * @return the priority
*/
public boolean hoverModeSelected();
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java
index 7af4d68ce8..e29c102bc2 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java
@@ -17,6 +17,7 @@ package docking.widgets;
import java.awt.*;
import java.awt.event.*;
+import java.awt.geom.Rectangle2D;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
@@ -25,7 +26,9 @@ import java.util.List;
import javax.swing.*;
import javax.swing.Timer;
+import generic.json.Json;
import generic.util.WindowUtilities;
+import ghidra.util.Msg;
import ghidra.util.bean.GGlassPane;
import ghidra.util.bean.GGlassPanePainter;
@@ -112,8 +115,8 @@ public class PopupWindow {
sourceMouseMotionListener = new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
- Point localPoint = e.getPoint();
+ Point localPoint = e.getPoint();
SwingUtilities.convertPointToScreen(localPoint, e.getComponent());
if (!neutralMotionZone.contains(localPoint)) {
hide();
@@ -121,7 +124,7 @@ public class PopupWindow {
else {
// If the user mouses around the neutral zone, then start the close timer. The
// timer will be reset if the user enters the popup.
- closeTimer.start();
+ closeTimer.restart();
}
e.consume(); // consume the event so that the source component doesn't processes it
}
@@ -237,16 +240,15 @@ public class PopupWindow {
int y = point.y + keepVisibleArea.height + Y_PADDING;
popupBounds.setLocation(x, y);
- WindowUtilities.ensureOnScreen(sourceComponent, popupBounds);
+ ensureSize(popupBounds);
Rectangle hoverArea = new Rectangle(point, keepVisibleArea);
- adjustBoundsForCursorLocation(popupBounds, hoverArea);
-
- neutralMotionZone = createNeutralMotionZone(popupBounds, hoverArea);
+ Rectangle adjustedBounds = adjustBoundsForCursorLocation(popupBounds, hoverArea);
+ neutralMotionZone = createNeutralMotionZone(adjustedBounds, hoverArea);
installDebugPainter(e);
- popup.setBounds(popupBounds);
+ popup.setBounds(adjustedBounds);
popup.setVisible(true);
removeOldPopupReferences();
@@ -254,19 +256,38 @@ public class PopupWindow {
VISIBLE_POPUPS.add(new WeakReference<>(this));
}
+ private void ensureSize(Rectangle popupBounds) {
+ Shape screenShape = WindowUtilities.getVisibleScreenBounds();
+ Rectangle screenBounds = screenShape.getBounds();
+ if (screenBounds.width < popupBounds.width) {
+ popupBounds.width = screenBounds.width / 2;
+ }
+
+ if (screenBounds.height < popupBounds.height) {
+ popupBounds.height = screenBounds.height / 2;
+ }
+ }
+
+ private void installDebugPainter(List
- * When the hoverArea is obscured, this method will first attempt to move the
- * bounds up if possible. If moving up is not possible due to space constraints, then this
- * method will try to shift the bounds to the right of the hover area. If this is not
- * possible, then the bounds will not be changed.
+ * When the hoverArea is obscured, this method will create a grid of possible locations
+ * in which to place the given bounds. The grid will be searched for the location that is
+ * closest to the hover area without touching it.
*
* @param bounds The bounds to move as necessary.
* @param hoverArea The area that should not be covered by the given bounds
@@ -274,28 +295,113 @@ public class PopupWindow {
* if possible.
*/
private Rectangle adjustBoundsForCursorLocation(Rectangle bounds, Rectangle hoverArea) {
- if (!bounds.intersects(hoverArea)) {
+ Shape screenShape = WindowUtilities.getVisibleScreenBounds();
+ Rectangle screenBounds = screenShape.getBounds();
+ if (!bounds.intersects(hoverArea) && screenBounds.contains(bounds)) {
return bounds;
}
- // first attempt to move the window--try to go up
- int movedY = hoverArea.y - bounds.height;
- boolean canMoveUp = movedY >= 0;
- if (canMoveUp) {
- // move the given bounds above the current point
- bounds.y = movedY;
+ // center bounds over hover area; we intend not to block the hover area
+ int dx = (hoverArea.width / 2) - (bounds.width / 2);
+ int dy = (hoverArea.height / 2) - (bounds.height / 2);
+ Point hoverCenter = bounds.getLocation();
+ hoverCenter.x += dx;
+ hoverCenter.y += dy;
+
+ List