Updated PopupWindow to allow clients to specify the window placement

algorithm
This commit is contained in:
dragonmacher 2023-09-29 11:59:01 -04:00
parent 54e0ab1a38
commit 6202221515
4 changed files with 55 additions and 6 deletions

View File

@ -27,6 +27,7 @@ import docking.widgets.PopupWindow;
import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.FieldLocation;
import docking.widgets.fieldpanel.support.HoverProvider;
import docking.widgets.shapes.PopupWindowPlacer;
import ghidra.app.services.HoverService;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
@ -42,7 +43,9 @@ public abstract class AbstractHoverProvider implements HoverProvider {
private static final Comparator<HoverService> HOVER_PRIORITY_COMPARATOR =
(service1, service2) -> service2.getPriority() - service1.getPriority();
protected HoverService activeHoverService;
protected PopupWindow popupWindow;
protected PopupWindowPlacer popupWindowPlacer;
protected final String windowName;
@ -80,6 +83,14 @@ public abstract class AbstractHoverProvider implements HoverProvider {
}
}
/**
* Sets the object that decides where to place the popup window.
* @param popupWindowPlacer the placer
*/
public void setPopupPlacer(PopupWindowPlacer popupWindowPlacer) {
this.popupWindowPlacer = popupWindowPlacer;
}
public boolean isForcePopups() {
return false; // the default implementation is to be disabled if tip windows are disabled
}
@ -176,8 +187,13 @@ public abstract class AbstractHoverProvider implements HoverProvider {
activeWindow = JOptionPane.getRootFrame();
}
if (popupWindow != null) {
popupWindow.dispose();
}
popupWindow = new PopupWindow(activeWindow, comp);
popupWindow.setWindowName(windowName);
popupWindow.setPopupPlacer(popupWindowPlacer);
popupWindow.addComponentListener(new ComponentAdapter() {
@Override

View File

@ -65,6 +65,7 @@ public class PopupWindow {
private Rectangle mouseMovementArea;
private JWindow popup;
private Component sourceComponent;
private PopupWindowPlacer popupWindowPlacer = DEFAULT_WINDOW_PLACER;
private MouseMotionListener sourceMouseMotionListener;
private MouseListener sourceMouseListener;
@ -227,9 +228,18 @@ public class PopupWindow {
closeTimer.setRepeats(false);
}
/**
* Sets the object that decides where to place the popup window.
* @param popupWindowPlacer the placer
*/
public void setPopupPlacer(PopupWindowPlacer popupWindowPlacer) {
this.popupWindowPlacer =
popupWindowPlacer == null ? DEFAULT_WINDOW_PLACER : popupWindowPlacer;
}
public void showOffsetPopup(MouseEvent e, Rectangle keepVisibleSize, boolean forceShow) {
if (forceShow || DockingUtils.isTipWindowEnabled()) {
doShowPopup(e, keepVisibleSize, DEFAULT_WINDOW_PLACER);
doShowPopup(e, keepVisibleSize, popupWindowPlacer);
}
}
@ -251,7 +261,7 @@ public class PopupWindow {
*/
public void showPopup(MouseEvent e, boolean forceShow) {
if (forceShow || DockingUtils.isTipWindowEnabled()) {
doShowPopup(e, null, DEFAULT_WINDOW_PLACER);
doShowPopup(e, null, popupWindowPlacer);
}
}

View File

@ -115,7 +115,7 @@ import ghidra.util.exception.AssertException;
* and <B>minorEnd</B> {@link Location Locations}. The major Location specifies the <B>edge</B>
* for an {@link EdgePopupPlacer} and the minorBegin Location specifies the placement <B>cell</B>
* on this edge and the minorEnds specifies the last cell (amount of shift allowed), starting
* from the minorBegin Location. For a CENTER minorBeing Location, the minorEnd cell may be
* from the minorBegin Location. For a CENTER minorBegin Location, the minorEnd cell may be
* any of the three allowed Locations on that major edge as well as null, representing that a
* shift is allowed in either direction. When the minorEnd Location is set to the minorBegin
* Location, then no shift is permitted.

View File

@ -15,10 +15,12 @@
*/
package docking.widgets.shapes;
import docking.widgets.shapes.PopupWindowPlacer.*;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.Arrays;
import docking.widgets.shapes.PopupWindowPlacer.*;
/**
* This class builds a PopWindowPlacer that can have subsequent PopWindowPlacers.
* <p>
@ -281,7 +283,8 @@ public class PopupWindowPlacerBuilder {
*/
public PopupWindowPlacerBuilder edge(Location major, Location... minors) {
if (minors.length > 3) {
throw new IllegalArgumentException("Too many preferred Locations: " + Arrays.toString(minors));
throw new IllegalArgumentException(
"Too many preferred Locations: " + Arrays.toString(minors));
}
for (Location minor : minors) {
if (!major.validMinor(minor)) {
@ -428,4 +431,24 @@ public class PopupWindowPlacerBuilder {
return this;
}
/**
* A method that allows clients to specify an exact rectangle to be used. This method can be
* used to hardcode a rectangle to use when the placement algorithm specified earlier in the
* builder chain has failed.
*
* @param r the rectangle
* @return this builder
*/
public PopupWindowPlacerBuilder useRectangle(Rectangle r) {
add(new PopupWindowPlacer() {
@Override
protected Rectangle getMyPlacement(Dimension toBePlaced, Rectangle innerBounds,
Rectangle outerBounds) {
return r;
}
});
return this;
}
}