mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -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);
|
popupWindow.showPopup(event);
|
||||||
}
|
}
|
||||||
else {
|
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);
|
popupWindow.showOffsetPopup(event, keepVisibleArea);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,16 @@ import java.util.List;
|
|||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
|
|
||||||
|
import docking.widgets.shapes.*;
|
||||||
import generic.util.WindowUtilities;
|
import generic.util.WindowUtilities;
|
||||||
import ghidra.util.bean.GGlassPane;
|
import ghidra.util.bean.GGlassPane;
|
||||||
import ghidra.util.bean.GGlassPanePainter;
|
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 {
|
public class PopupWindow {
|
||||||
private static final int X_PADDING = 25;
|
private static final int X_PADDING = 25;
|
||||||
private static final int Y_PADDING = 25;
|
private static final int Y_PADDING = 25;
|
||||||
@@ -302,15 +308,12 @@ public class PopupWindow {
|
|||||||
// painters.add(painter);
|
// painters.add(painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for debug
|
|
||||||
// private static List<GGlassPanePainter> painters = new ArrayList<>();
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Inner Classes
|
// Inner Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
// for debug
|
// 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) */
|
/** Paints shapes used by this class (useful for debugging) */
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package docking.widgets;
|
package docking.widgets.shapes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies location and metrics for {@link PopupWindowPlacer}.
|
* Specifies location and metrics for {@link PopupWindowPlacer}.
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package docking.widgets;
|
package docking.widgets.shapes;
|
||||||
|
|
||||||
import java.awt.*;
|
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
|
* 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,
|
* in circumstances where the developer believes such an assertion is not possible,
|
||||||
* such as when allowing an overlapping placement solution.
|
* such as when allowing an overlapping placement solution.
|
||||||
|
*
|
||||||
|
* @see PopupWindowPlacerBuilder
|
||||||
*/
|
*/
|
||||||
public abstract class PopupWindowPlacer {
|
public abstract class PopupWindowPlacer {
|
||||||
|
|
||||||
@@ -144,10 +146,10 @@ public abstract class PopupWindowPlacer {
|
|||||||
private PopupWindowPlacer next = null;
|
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() {
|
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 major edge
|
||||||
* @param minorBegin start location on edge
|
* @param minorBegin start location on edge
|
||||||
* @param minorEnd end location on edge
|
* @param minorEnd end location on edge
|
||||||
|
*
|
||||||
|
* @see PopupWindowPlacerBuilder
|
||||||
*/
|
*/
|
||||||
public PopupWindowPlacer(Location major, Location minorBegin, Location minorEnd) {
|
public PopupWindowPlacer(Location major, Location minorBegin, Location minorEnd) {
|
||||||
if (major == Location.CENTER) {
|
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
|
* 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.
|
* horizontal. These two situations are independent, but the same algorithm is used.
|
||||||
* <p>
|
* <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.
|
* Note: smaller values are up and bigger values are down, in the presentation below.
|
||||||
* <p>
|
* <p>
|
||||||
* In trying to allay some confusion (yes it can be confusing), note that for any given major
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* else
|
||||||
* no solution
|
* no solution
|
||||||
* </pre>
|
* </pre>
|
||||||
* ... or...
|
* or
|
||||||
* <pre>
|
* <pre>
|
||||||
* <B>lesserLocation</B>
|
* <B>lesserLocation</B>
|
||||||
* <B>→</B> <B>lesserBoundedLocation</B> (≥ <B>lesserLocation</B>)
|
* <B>→</B> <B>lesserBoundedLocation</B> (≥ <B>lesserLocation</B>)
|
||||||
@@ -369,7 +373,7 @@ public abstract class PopupWindowPlacer {
|
|||||||
* else
|
* else
|
||||||
* solution is centerLocation
|
* solution is centerLocation
|
||||||
* </pre>
|
* </pre>
|
||||||
* ... or...
|
* or
|
||||||
* <pre>
|
* <pre>
|
||||||
* <B>lesserLocation</B>
|
* <B>lesserLocation</B>
|
||||||
* <B>centerLocation</B>
|
* <B>centerLocation</B>
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.
|
* 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
|
* placers, and a clean-up <B>assert</B> placer. Additionally, there are <B>rotational</B> placers
|
||||||
* that are composed of edge placers.
|
* that are composed of edge placers.
|
||||||
* <p>
|
* <p>
|
||||||
* <B>EDGE PLACERS</B>
|
* <BR>
|
||||||
|
* <BR>
|
||||||
|
*
|
||||||
|
* <H1>Edge Placers</H1>
|
||||||
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The <B>edge</B> placers are the leftEdge, rightEdge, topEdge, and bottomEdge methods that take
|
* 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
|
* 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,
|
* 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.
|
* <code>Location.TOP</code> is only valid for left and right edges.
|
||||||
* <p>
|
* <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
|
* 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
|
* 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
|
* 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
|
* 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>).
|
* placement cell twice (e.g., <code>rightEdge(Location.TOP, Location.TOP)</code>).
|
||||||
* <p>
|
* <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
|
* 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,
|
* that the second argument is automatically set to the nearest neighboring cell. Thus,
|
||||||
* <code>rightEdge(Location.TOP)</code> is the same as
|
* <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
|
* <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.
|
* and the second being the TOP or LEFT cell.
|
||||||
* <p>
|
* <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
|
* 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.
|
* to BOTTOM or RIGHT for the first and TOP or LEFT for the second.
|
||||||
* <p>
|
* <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
|
* 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:
|
* shift, then tries the top of the right edge with no shift, then top center with no shift:
|
||||||
* <pre>
|
* <pre>
|
||||||
@@ -77,7 +93,11 @@ import docking.widgets.PopupWindowPlacer.*;
|
|||||||
* .topEdge(Location.CENTER);
|
* .topEdge(Location.CENTER);
|
||||||
* .build();</pre>
|
* .build();</pre>
|
||||||
* <p>
|
* <p>
|
||||||
* <B>ROTATIONAL PLACERS</B>
|
* <BR>
|
||||||
|
* <BR>
|
||||||
|
*
|
||||||
|
* <H1>Rotational Placers</H1>
|
||||||
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* There are clockwise and counter-clockwise rotational placers that built up from edge placers.
|
* There are clockwise and counter-clockwise rotational placers that built up from edge placers.
|
||||||
* These are:
|
* 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
|
* 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.
|
* there was not a previous placer, then the BOTTOM RIGHT cell is chosen as the starting cell.
|
||||||
* <p>
|
* <p>
|
||||||
* <B>OVERLAPPING CORNER PLACER</B>
|
* <BR>
|
||||||
|
* <BR>
|
||||||
|
*
|
||||||
|
* <H1>Overlapping Corner Placer</H1>
|
||||||
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* There is one corner placer, <code>leastOverlapCorner()</code>. This placer tries to make a
|
* 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
|
* 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
|
* top left. Unless ill-constructed (sized of context area, screen, and pop-up dimension), this
|
||||||
* placer should always find a solution.
|
* placer should always find a solution.
|
||||||
* <p>
|
* <p>
|
||||||
* <B>ASSERT PLACER</B>
|
* <BR>
|
||||||
|
* <BR>
|
||||||
|
*
|
||||||
|
* <H1>Assert Placer</H1>
|
||||||
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>throwsAssertException()</code> placer is available, which automatically throws an
|
* 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
|
* 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
|
* <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.
|
* the <code>null</code> return value that would be returned from previous placement attempts.
|
||||||
* <p>
|
* <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
|
* 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 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:
|
* 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package docking.widgets;
|
package docking.widgets.shapes;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
Reference in New Issue
Block a user