mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-25 17:00:36 -09:00
GP-875 - Popup window placement integration
This commit is contained in:
@@ -192,9 +192,20 @@ public abstract class AbstractHoverProvider implements HoverProvider {
|
||||
popupWindow.showPopup(event);
|
||||
}
|
||||
else {
|
||||
int xOffset = 50;// magic: trial and error
|
||||
Dimension size = fieldBounds.getSize();
|
||||
Dimension keepVisibleArea = new Dimension(xOffset, size.height);
|
||||
|
||||
//
|
||||
// Make an area over which to show the popup. The popup should not cover this area.
|
||||
// The field that is hovered may be too big to be this area, as a big field may cause
|
||||
// the popup to be too far away from the cursor.
|
||||
//
|
||||
// Use the mouse point and then create an area (based on trial-and-error) that should
|
||||
// not be occluded.
|
||||
//
|
||||
int horizontalPad = 100;
|
||||
int verticalPad = 50;
|
||||
Rectangle keepVisibleArea = new Rectangle(event.getPoint());
|
||||
keepVisibleArea.grow(horizontalPad, verticalPad);
|
||||
|
||||
popupWindow.showOffsetPopup(event, keepVisibleArea);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,16 @@ import java.util.List;
|
||||
import javax.swing.*;
|
||||
import javax.swing.Timer;
|
||||
|
||||
import docking.widgets.shapes.*;
|
||||
import generic.util.WindowUtilities;
|
||||
import ghidra.util.bean.GGlassPane;
|
||||
import ghidra.util.bean.GGlassPanePainter;
|
||||
|
||||
/**
|
||||
* A generic window intended to be used as a temporary window to show information. This window is
|
||||
* designed to stay open as long as the user mouses over the window. Once the user mouses away,
|
||||
* the window will be closed.
|
||||
*/
|
||||
public class PopupWindow {
|
||||
private static final int X_PADDING = 25;
|
||||
private static final int Y_PADDING = 25;
|
||||
@@ -302,15 +308,12 @@ public class PopupWindow {
|
||||
// painters.add(painter);
|
||||
}
|
||||
|
||||
// for debug
|
||||
// private static List<GGlassPanePainter> painters = new ArrayList<>();
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
||||
// for debug
|
||||
//private static List<GGlassPanePainter> painters = new ArrayList<>();
|
||||
// private static List<GGlassPanePainter> painters = new ArrayList<>();
|
||||
|
||||
/** Paints shapes used by this class (useful for debugging) */
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets;
|
||||
package docking.widgets.shapes;
|
||||
|
||||
/**
|
||||
* Specifies location and metrics for {@link PopupWindowPlacer}.
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets;
|
||||
package docking.widgets.shapes;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -134,6 +134,8 @@ import ghidra.util.exception.AssertException;
|
||||
* This last placer, when chosen, serves as an assert condition, which is helpful
|
||||
* in circumstances where the developer believes such an assertion is not possible,
|
||||
* such as when allowing an overlapping placement solution.
|
||||
*
|
||||
* @see PopupWindowPlacerBuilder
|
||||
*/
|
||||
public abstract class PopupWindowPlacer {
|
||||
|
||||
@@ -144,10 +146,10 @@ public abstract class PopupWindowPlacer {
|
||||
private PopupWindowPlacer next = null;
|
||||
|
||||
/**
|
||||
* Constructor only for classes that do you use Preferences
|
||||
* Constructor only for classes that do not use placement preferences
|
||||
*/
|
||||
public PopupWindowPlacer() {
|
||||
// Only for implementations that do not use Preferences
|
||||
// Only for implementations that do not use placement preferences
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,6 +158,8 @@ public abstract class PopupWindowPlacer {
|
||||
* @param major edge
|
||||
* @param minorBegin start location on edge
|
||||
* @param minorEnd end location on edge
|
||||
*
|
||||
* @see PopupWindowPlacerBuilder
|
||||
*/
|
||||
public PopupWindowPlacer(Location major, Location minorBegin, Location minorEnd) {
|
||||
if (major == Location.CENTER) {
|
||||
@@ -263,7 +267,7 @@ public abstract class PopupWindowPlacer {
|
||||
* and the minor axis being vertical; the major axis being vertical, and the minor axis being
|
||||
* horizontal. These two situations are independent, but the same algorithm is used.
|
||||
* <p>
|
||||
* <B>Algorithm Design...</B><p>
|
||||
* <B>Algorithm Design</B><p>
|
||||
* Note: smaller values are up and bigger values are down, in the presentation below.
|
||||
* <p>
|
||||
* In trying to allay some confusion (yes it can be confusing), note that for any given major
|
||||
@@ -283,7 +287,7 @@ public abstract class PopupWindowPlacer {
|
||||
* Keeping with the original right edge scenario begun above, we are trying to find a minor
|
||||
* axis placement on the right (major) edge. For this placement, one can refer to
|
||||
* documentation elsewhere in this class, but essentially, we are trying to place a popup
|
||||
* area against a context rectangle without exceeded the outer bounds (screen) rectangle. But,
|
||||
* area against a context rectangle without exceeding the outer bounds (screen) rectangle. But,
|
||||
* again, we are only considering the placement against the right edge already chosen and only
|
||||
* trying to fit in the vertical dimension against this edge. Thus, this algorithm only needs
|
||||
* values for this one dimension. These are the length of the placement area in this one
|
||||
@@ -348,7 +352,7 @@ public abstract class PopupWindowPlacer {
|
||||
* else
|
||||
* no solution
|
||||
* </pre>
|
||||
* ... or...
|
||||
* or
|
||||
* <pre>
|
||||
* <B>lesserLocation</B>
|
||||
* <B>→</B> <B>lesserBoundedLocation</B> (≥ <B>lesserLocation</B>)
|
||||
@@ -369,7 +373,7 @@ public abstract class PopupWindowPlacer {
|
||||
* else
|
||||
* solution is centerLocation
|
||||
* </pre>
|
||||
* ... or...
|
||||
* or
|
||||
* <pre>
|
||||
* <B>lesserLocation</B>
|
||||
* <B>centerLocation</B>
|
||||
@@ -13,9 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets;
|
||||
package docking.widgets.shapes;
|
||||
|
||||
import docking.widgets.PopupWindowPlacer.*;
|
||||
import docking.widgets.shapes.PopupWindowPlacer.*;
|
||||
|
||||
/**
|
||||
* This class builds a PopWindowPlacer that can have subsequent PopWindowPlacers.
|
||||
@@ -24,7 +24,11 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* placers, and a clean-up <B>assert</B> placer. Additionally, there are <B>rotational</B> placers
|
||||
* that are composed of edge placers.
|
||||
* <p>
|
||||
* <B>EDGE PLACERS</B>
|
||||
* <BR>
|
||||
* <BR>
|
||||
*
|
||||
* <H1>Edge Placers</H1>
|
||||
*
|
||||
* <p>
|
||||
* The <B>edge</B> placers are the leftEdge, rightEdge, topEdge, and bottomEdge methods that take
|
||||
* Location arguments that one can think of as "cells" for optimal placement, but which have some
|
||||
@@ -38,7 +42,10 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* same way for each method, though some arguments are not valid for some edges; for instance,
|
||||
* <code>Location.TOP</code> is only valid for left and right edges.
|
||||
* <p>
|
||||
* <B>Two or More Location Arguments</B><p>
|
||||
*
|
||||
* <H2>Two or More Location Arguments</H2>
|
||||
*
|
||||
* <p>
|
||||
* When two or more arguments are used, the first argument specifies the nominal placement cell
|
||||
* and the second argument specifies how far the solution is allowed to shift. If a solution is
|
||||
* not found and if there are more than two arguments, another placement attempt is made where
|
||||
@@ -46,7 +53,10 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* far the solution is allowed to shift. To specify a "no-shift" solution, one specifies the same
|
||||
* placement cell twice (e.g., <code>rightEdge(Location.TOP, Location.TOP)</code>).
|
||||
* <p>
|
||||
* <B>One Location Argument</B><p>
|
||||
*
|
||||
* <H2>One Location Argument</H2>
|
||||
*
|
||||
* <p>
|
||||
* When one argument is used, the solution is the same as when two arguments are specified except
|
||||
* that the second argument is automatically set to the nearest neighboring cell. Thus,
|
||||
* <code>rightEdge(Location.TOP)</code> is the same as
|
||||
@@ -54,11 +64,17 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* <code>Location.CENTER</code>, two attempts are built, the first being the BOTTOM or RIGHT cell
|
||||
* and the second being the TOP or LEFT cell.
|
||||
* <p>
|
||||
* <B>No Arguments</B><p>
|
||||
*
|
||||
* <H2>No Arguments</H2>
|
||||
*
|
||||
* <p>
|
||||
* When no arguments are specified, two arguments to the underlying placer are automatically set
|
||||
* to BOTTOM or RIGHT for the first and TOP or LEFT for the second.
|
||||
* <p>
|
||||
* <B>Examples</B><p>
|
||||
*
|
||||
* <H2>Examples</H2>
|
||||
*
|
||||
* <p>
|
||||
* Builds a placer that first attempts a placement at the bottom of the right edge with no
|
||||
* shift, then tries the top of the right edge with no shift, then top center with no shift:
|
||||
* <pre>
|
||||
@@ -77,7 +93,11 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* .topEdge(Location.CENTER);
|
||||
* .build();</pre>
|
||||
* <p>
|
||||
* <B>ROTATIONAL PLACERS</B>
|
||||
* <BR>
|
||||
* <BR>
|
||||
*
|
||||
* <H1>Rotational Placers</H1>
|
||||
*
|
||||
* <p>
|
||||
* There are clockwise and counter-clockwise rotational placers that built up from edge placers.
|
||||
* These are:
|
||||
@@ -96,7 +116,11 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* except that they start at the "beginning" cell where the most previous placer had left off. If
|
||||
* there was not a previous placer, then the BOTTOM RIGHT cell is chosen as the starting cell.
|
||||
* <p>
|
||||
* <B>OVERLAPPING CORNER PLACER</B>
|
||||
* <BR>
|
||||
* <BR>
|
||||
*
|
||||
* <H1>Overlapping Corner Placer</H1>
|
||||
*
|
||||
* <p>
|
||||
* There is one corner placer, <code>leastOverlapCorner()</code>. This placer tries to make a
|
||||
* placement at each of the corners of the context area and shifts into the context region as much
|
||||
@@ -106,7 +130,11 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* top left. Unless ill-constructed (sized of context area, screen, and pop-up dimension), this
|
||||
* placer should always find a solution.
|
||||
* <p>
|
||||
* <B>ASSERT PLACER</B>
|
||||
* <BR>
|
||||
* <BR>
|
||||
*
|
||||
* <H1>Assert Placer</H1>
|
||||
*
|
||||
* <p>
|
||||
* The <code>throwsAssertException()</code> placer is available, which automatically throws an
|
||||
* AssertException. This placer is only intended to be used by the client in such as case when
|
||||
@@ -114,7 +142,12 @@ import docking.widgets.PopupWindowPlacer.*;
|
||||
* <code>leastOverlapCorner()</code> placer. This just throws an exception instead of returning
|
||||
* the <code>null</code> return value that would be returned from previous placement attempts.
|
||||
* <p>
|
||||
* <B>COMPOSITE EXAMPLES</B><p>
|
||||
* <BR>
|
||||
* <BR>
|
||||
*
|
||||
* <H1>Composite Placer</H1>
|
||||
*
|
||||
* <p>
|
||||
* Builds a placer that first attempts a placement at the right edge from bottom to top, then
|
||||
* left edge from bottom to top, then top edge from right to left, then bottom edge from right to
|
||||
* left, followed by a least-overlap-corner solution, followed by a failure assert:
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets;
|
||||
package docking.widgets.shapes;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
Reference in New Issue
Block a user