GP-5084 Adding ability to choose which corner the function graph satellite appears in.

This commit is contained in:
ghidragon
2024-12-06 18:42:28 -05:00
parent c5b753e881
commit d31c78cd9d
5 changed files with 155 additions and 11 deletions
@@ -137,6 +137,15 @@
hand corner of the graph and is only visible if the Satellite View is hidden or
undocked.</P>
</BLOCKQUOTE>
<H3><A name="Satellite_Location"></A>Docked Satellite Location</H3>
<BLOCKQUOTE>
<P>When the Satellite View is attached, or <B>docked</B>, to the Primary View, you
can choose which corner to show the satellite view. To change the
corner, right-click in the graph, select <B>Docked Satellite Position</B> and then
select the appropriate sub-menu for the desired corner.<P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2><A name="Vertices"></A>Vertices (Blocks)</H2>
@@ -266,6 +266,14 @@
hand corner of the graph and is only visible if the Satellite View is hidden or
undocked.</P>
</BLOCKQUOTE>
<H3><A name="Satellite_Location"></A>Docked Satellite Location</H3>
<BLOCKQUOTE>
<P>When the Satellite View is attached, or <B>docked</B>, to the Primary View, you
can choose which corner to show the satellite view. To change the
corner, right-click in the graph, select <B>Docked Satellite Position</B> and then
select the appropriate sub-menu for the desired corner.<P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2><A name="Options"></A>Options</H2>
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,6 +15,8 @@
*/
package ghidra.graph.featurette;
import static ghidra.graph.viewer.GraphComponent.SatellitePosition.*;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
@@ -29,6 +31,7 @@ import ghidra.framework.options.SaveState;
import ghidra.graph.VisualGraph;
import ghidra.graph.VisualGraphComponentProvider;
import ghidra.graph.viewer.*;
import ghidra.graph.viewer.GraphComponent.SatellitePosition;
import ghidra.graph.viewer.actions.*;
import ghidra.util.HelpLocation;
@@ -56,9 +59,14 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
private static final String DISPLAY_SATELLITE = "DISPLAY_SATELLITE";
private static final String DOCK_SATELLITE = "DOCK_SATELLITE";
private static final String DOCK_SATELLITE_POSITION = "DOCK_SATELLITE_POSITION";
private ToggleDockingAction toggleSatelliteAction;
private ToggleDockingAction dockSatelliteAction;
private ToggleDockingAction upperLeftAction;
private ToggleDockingAction upperRightAction;
private ToggleDockingAction lowerLeftAction;
private ToggleDockingAction lowerRightAction;
private Tool tool;
private VisualGraphView<?, ?, ?> view;
@@ -75,6 +83,7 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
public void writeConfigState(SaveState saveState) {
saveState.putBoolean(DOCK_SATELLITE, dockSatelliteAction.isSelected());
saveState.putBoolean(DISPLAY_SATELLITE, toggleSatelliteAction.isSelected());
saveState.putString(DOCK_SATELLITE_POSITION, view.getSatellitePosition().toString());
}
@Override
@@ -90,6 +99,25 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
boolean showSatellite = saveState.getBoolean(DISPLAY_SATELLITE, true);
toggleSatelliteAction.setSelected(showSatellite);
view.setSatelliteVisible(showSatellite);
String positionString = saveState.getString(DOCK_SATELLITE_POSITION, LOWER_RIGHT.name());
SatellitePosition position = SatellitePosition.valueOf(positionString);
view.setSatellitePosition(position);
deselectAllSatellitePositions();
switch (position) {
case LOWER_LEFT:
lowerLeftAction.setSelected(true);
break;
case LOWER_RIGHT:
lowerRightAction.setSelected(true);
break;
case UPPER_LEFT:
upperLeftAction.setSelected(true);
break;
case UPPER_RIGHT:
upperRightAction.setSelected(true);
break;
}
}
@Override
@@ -185,9 +213,20 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
dockSatelliteAction.setHelpLocation(
new HelpLocation("FunctionCallGraphPlugin", "Satellite_View"));
// Note: this is not a local action, since it should appear in satellite and the main view
upperLeftAction = new SatellitePositionAction("Upper Left", UPPER_LEFT, provider);
upperRightAction = new SatellitePositionAction("Upper Right", UPPER_RIGHT, provider);
lowerLeftAction = new SatellitePositionAction("Lower Left", LOWER_LEFT, provider);
lowerRightAction = new SatellitePositionAction("Lower Right", LOWER_RIGHT, provider);
lowerRightAction.setSelected(true);
// Note: these are not local actions, since they should appear in satellite and the main view
tool.addAction(toggleSatelliteAction);
tool.addAction(dockSatelliteAction);
tool.addAction(upperLeftAction);
tool.addAction(upperRightAction);
tool.addAction(lowerLeftAction);
tool.addAction(lowerRightAction);
}
@Override
@@ -197,6 +236,13 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
}
}
public void deselectAllSatellitePositions() {
upperLeftAction.setSelected(false);
upperRightAction.setSelected(false);
lowerLeftAction.setSelected(false);
lowerRightAction.setSelected(false);
}
// only remove the provider if the user had docked the satellite
private void closeSatelliteProvider(boolean remove) {
if (satelliteProvider == null) {
@@ -299,4 +345,43 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
}
}
}
private class SatellitePositionAction extends ToggleDockingAction {
private SatellitePosition position;
private ComponentProvider provider;
public SatellitePositionAction(String name, SatellitePosition posiiton,
ComponentProvider provider) {
super(name, owner);
this.position = posiiton;
this.provider = provider;
setPopupMenuData(new MenuData(new String[] { "Docked Satellite Position", name }));
setHelpLocation(new HelpLocation("FunctionCallGraphPlugin", "Satellite_Location"));
}
@Override
public void actionPerformed(ActionContext context) {
deselectAllSatellitePositions();
setSelected(true);
view.setSatellitePosition(position);
}
@Override
public boolean isAddToPopup(ActionContext context) {
ComponentProvider componentProvider = context.getComponentProvider();
if (componentProvider != provider && componentProvider != satelliteProvider) {
// appear in satellite and the main provider
return false;
}
if (context instanceof VisualGraphActionContext vgContext) {
return vgContext.shouldShowSatelliteActions();
}
return false;
}
}
}
@@ -83,6 +83,9 @@ import util.CollectionUtils;
* @see GraphViewer
*/
public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G extends VisualGraph<V, E>> {
public enum SatellitePosition {
UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
}
private static final double PARENT_TO_SATELLITE_RATIO = 4;// 2.5 smaller view seems better
private static final int MINIMUM_SATELLITE_WIDTH = 150;
@@ -130,6 +133,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
private Dimension lastSize;
protected VisualGraphOptions vgOptions = new VisualGraphOptions();
private SatellitePosition dockedSatellitePosition = SatellitePosition.UPPER_RIGHT;
public GraphComponent(G graph) {
@@ -782,6 +786,15 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
updateSatellite(docked, true);
}
public SatellitePosition getSatellitePosition() {
return dockedSatellitePosition;
}
public void setSatellitePosition(SatellitePosition position) {
dockedSatellitePosition = position;
updateSatellite(satelliteViewer.isDocked(), isSatelliteShowing());
}
public void setSatelliteVisible(boolean visible) {
if (isSatelliteShowing() == visible) {
@@ -823,9 +836,8 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
staleGraphViewPanel.setBounds(x, y, stalePanelSize.width, stalePanelSize.height);
Dimension buttonSize = showUndockedSatelliteButton.getPreferredSize();
x = parentSize.width - buttonSize.width;
y = parentSize.height - buttonSize.height;
showUndockedSatelliteButton.setBounds(x, y, buttonSize.width, buttonSize.height);
Point p = getSatellitePosition(parentSize, buttonSize);
showUndockedSatelliteButton.setBounds(p.x, p.y, buttonSize.width, buttonSize.height);
lastSize = new Dimension(parentSize.width, parentSize.height);
}
@@ -843,15 +855,30 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
int newWidth = getNewBoundsSize(parentSize, satelliteSize);
satelliteSize.width = newWidth;
satelliteSize.height = newWidth;
int x = parentSize.width - satelliteSize.width;
int y = parentSize.height - satelliteSize.height;
satelliteViewer.setBounds(x, y, satelliteSize.width, satelliteSize.height);
Point p = getSatellitePosition(parentSize, satelliteSize);
satelliteViewer.setBounds(p.x, p.y, satelliteSize.width, satelliteSize.height);
}
VisualGraphViewUpdater<V, E> viewUpdater = getViewUpdater();
viewUpdater.fitGraphToViewerNow(satelliteViewer);
}
private Point getSatellitePosition(Dimension parentSize, Dimension satelliteSize) {
int x = parentSize.width - satelliteSize.width;
int y = parentSize.height - satelliteSize.height;
switch (dockedSatellitePosition) {
case LOWER_LEFT:
return new Point(0, y);
case UPPER_LEFT:
return new Point(0, 0);
case UPPER_RIGHT:
return new Point(x, 0);
case LOWER_RIGHT:
default:
return new Point(x, y);
}
}
private int getNewBoundsSize(Dimension parentBounds, Dimension satelliteBounds) {
double newSatelliteHeight = parentBounds.height / PARENT_TO_SATELLITE_RATIO;
double newSatelliteWidth = parentBounds.width / PARENT_TO_SATELLITE_RATIO;
@@ -1259,4 +1286,5 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
// stub
}
}
}
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,6 +29,7 @@ import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import generic.theme.Gui;
import ghidra.graph.VisualGraph;
import ghidra.graph.viewer.GraphComponent.SatellitePosition;
import ghidra.graph.viewer.event.mouse.VertexTooltipProvider;
import ghidra.graph.viewer.event.mouse.VisualGraphMousePlugin;
import ghidra.graph.viewer.layout.LayoutProvider;
@@ -124,6 +125,7 @@ public class VisualGraphView<V extends VisualVertex,
protected LayoutProvider<V, E, G> layoutProvider;
private final ScalingControl scaler = new VisualGraphScalingControl();
private SatellitePosition satellitePosition = SatellitePosition.LOWER_RIGHT;
public VisualGraphView() {
build();
@@ -263,6 +265,7 @@ public class VisualGraphView<V extends VisualVertex,
undockedSatelliteContentPanel.add(graphComponent.getSatelliteContentComponent());
undockedSatelliteContentPanel.validate();
}
graphComponent.setSatellitePosition(satellitePosition);
}
/*
@@ -421,6 +424,17 @@ public class VisualGraphView<V extends VisualVertex,
}
}
public void setSatellitePosition(SatellitePosition position) {
satellitePosition = position;
if (graphComponent != null) {
graphComponent.setSatellitePosition(position);
}
}
public SatellitePosition getSatellitePosition() {
return satellitePosition;
}
/**
* Returns whether the satellite intended to be docked. If this component is built, then
* a result of true means that the satellite is docked. If the component is not yet