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 hand corner of the graph and is only visible if the Satellite View is hidden or
undocked.</P> undocked.</P>
</BLOCKQUOTE> </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> </BLOCKQUOTE>
<H2><A name="Vertices"></A>Vertices (Blocks)</H2> <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 hand corner of the graph and is only visible if the Satellite View is hidden or
undocked.</P> undocked.</P>
</BLOCKQUOTE> </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> </BLOCKQUOTE>
<H2><A name="Options"></A>Options</H2> <H2><A name="Options"></A>Options</H2>
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,6 +15,8 @@
*/ */
package ghidra.graph.featurette; package ghidra.graph.featurette;
import static ghidra.graph.viewer.GraphComponent.SatellitePosition.*;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
@@ -29,6 +31,7 @@ import ghidra.framework.options.SaveState;
import ghidra.graph.VisualGraph; import ghidra.graph.VisualGraph;
import ghidra.graph.VisualGraphComponentProvider; import ghidra.graph.VisualGraphComponentProvider;
import ghidra.graph.viewer.*; import ghidra.graph.viewer.*;
import ghidra.graph.viewer.GraphComponent.SatellitePosition;
import ghidra.graph.viewer.actions.*; import ghidra.graph.viewer.actions.*;
import ghidra.util.HelpLocation; 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 DISPLAY_SATELLITE = "DISPLAY_SATELLITE";
private static final String DOCK_SATELLITE = "DOCK_SATELLITE"; private static final String DOCK_SATELLITE = "DOCK_SATELLITE";
private static final String DOCK_SATELLITE_POSITION = "DOCK_SATELLITE_POSITION";
private ToggleDockingAction toggleSatelliteAction; private ToggleDockingAction toggleSatelliteAction;
private ToggleDockingAction dockSatelliteAction; private ToggleDockingAction dockSatelliteAction;
private ToggleDockingAction upperLeftAction;
private ToggleDockingAction upperRightAction;
private ToggleDockingAction lowerLeftAction;
private ToggleDockingAction lowerRightAction;
private Tool tool; private Tool tool;
private VisualGraphView<?, ?, ?> view; private VisualGraphView<?, ?, ?> view;
@@ -75,6 +83,7 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
public void writeConfigState(SaveState saveState) { public void writeConfigState(SaveState saveState) {
saveState.putBoolean(DOCK_SATELLITE, dockSatelliteAction.isSelected()); saveState.putBoolean(DOCK_SATELLITE, dockSatelliteAction.isSelected());
saveState.putBoolean(DISPLAY_SATELLITE, toggleSatelliteAction.isSelected()); saveState.putBoolean(DISPLAY_SATELLITE, toggleSatelliteAction.isSelected());
saveState.putString(DOCK_SATELLITE_POSITION, view.getSatellitePosition().toString());
} }
@Override @Override
@@ -90,6 +99,25 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
boolean showSatellite = saveState.getBoolean(DISPLAY_SATELLITE, true); boolean showSatellite = saveState.getBoolean(DISPLAY_SATELLITE, true);
toggleSatelliteAction.setSelected(showSatellite); toggleSatelliteAction.setSelected(showSatellite);
view.setSatelliteVisible(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 @Override
@@ -185,9 +213,20 @@ public class VgSatelliteFeaturette<V extends VisualVertex,
dockSatelliteAction.setHelpLocation( dockSatelliteAction.setHelpLocation(
new HelpLocation("FunctionCallGraphPlugin", "Satellite_View")); 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(toggleSatelliteAction);
tool.addAction(dockSatelliteAction); tool.addAction(dockSatelliteAction);
tool.addAction(upperLeftAction);
tool.addAction(upperRightAction);
tool.addAction(lowerLeftAction);
tool.addAction(lowerRightAction);
} }
@Override @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 // only remove the provider if the user had docked the satellite
private void closeSatelliteProvider(boolean remove) { private void closeSatelliteProvider(boolean remove) {
if (satelliteProvider == null) { 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 * @see GraphViewer
*/ */
public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G extends VisualGraph<V, E>> { 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 double PARENT_TO_SATELLITE_RATIO = 4;// 2.5 smaller view seems better
private static final int MINIMUM_SATELLITE_WIDTH = 150; 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; private Dimension lastSize;
protected VisualGraphOptions vgOptions = new VisualGraphOptions(); protected VisualGraphOptions vgOptions = new VisualGraphOptions();
private SatellitePosition dockedSatellitePosition = SatellitePosition.UPPER_RIGHT;
public GraphComponent(G graph) { public GraphComponent(G graph) {
@@ -782,6 +786,15 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
updateSatellite(docked, true); updateSatellite(docked, true);
} }
public SatellitePosition getSatellitePosition() {
return dockedSatellitePosition;
}
public void setSatellitePosition(SatellitePosition position) {
dockedSatellitePosition = position;
updateSatellite(satelliteViewer.isDocked(), isSatelliteShowing());
}
public void setSatelliteVisible(boolean visible) { public void setSatelliteVisible(boolean visible) {
if (isSatelliteShowing() == 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); staleGraphViewPanel.setBounds(x, y, stalePanelSize.width, stalePanelSize.height);
Dimension buttonSize = showUndockedSatelliteButton.getPreferredSize(); Dimension buttonSize = showUndockedSatelliteButton.getPreferredSize();
x = parentSize.width - buttonSize.width; Point p = getSatellitePosition(parentSize, buttonSize);
y = parentSize.height - buttonSize.height; showUndockedSatelliteButton.setBounds(p.x, p.y, buttonSize.width, buttonSize.height);
showUndockedSatelliteButton.setBounds(x, y, buttonSize.width, buttonSize.height);
lastSize = new Dimension(parentSize.width, parentSize.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); int newWidth = getNewBoundsSize(parentSize, satelliteSize);
satelliteSize.width = newWidth; satelliteSize.width = newWidth;
satelliteSize.height = newWidth; satelliteSize.height = newWidth;
int x = parentSize.width - satelliteSize.width; Point p = getSatellitePosition(parentSize, satelliteSize);
int y = parentSize.height - satelliteSize.height; satelliteViewer.setBounds(p.x, p.y, satelliteSize.width, satelliteSize.height);
satelliteViewer.setBounds(x, y, satelliteSize.width, satelliteSize.height);
} }
VisualGraphViewUpdater<V, E> viewUpdater = getViewUpdater(); VisualGraphViewUpdater<V, E> viewUpdater = getViewUpdater();
viewUpdater.fitGraphToViewerNow(satelliteViewer); 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) { private int getNewBoundsSize(Dimension parentBounds, Dimension satelliteBounds) {
double newSatelliteHeight = parentBounds.height / PARENT_TO_SATELLITE_RATIO; double newSatelliteHeight = parentBounds.height / PARENT_TO_SATELLITE_RATIO;
double newSatelliteWidth = parentBounds.width / 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 // stub
} }
} }
} }
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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 edu.uci.ics.jung.visualization.control.ScalingControl;
import generic.theme.Gui; import generic.theme.Gui;
import ghidra.graph.VisualGraph; import ghidra.graph.VisualGraph;
import ghidra.graph.viewer.GraphComponent.SatellitePosition;
import ghidra.graph.viewer.event.mouse.VertexTooltipProvider; import ghidra.graph.viewer.event.mouse.VertexTooltipProvider;
import ghidra.graph.viewer.event.mouse.VisualGraphMousePlugin; import ghidra.graph.viewer.event.mouse.VisualGraphMousePlugin;
import ghidra.graph.viewer.layout.LayoutProvider; import ghidra.graph.viewer.layout.LayoutProvider;
@@ -124,6 +125,7 @@ public class VisualGraphView<V extends VisualVertex,
protected LayoutProvider<V, E, G> layoutProvider; protected LayoutProvider<V, E, G> layoutProvider;
private final ScalingControl scaler = new VisualGraphScalingControl(); private final ScalingControl scaler = new VisualGraphScalingControl();
private SatellitePosition satellitePosition = SatellitePosition.LOWER_RIGHT;
public VisualGraphView() { public VisualGraphView() {
build(); build();
@@ -263,6 +265,7 @@ public class VisualGraphView<V extends VisualVertex,
undockedSatelliteContentPanel.add(graphComponent.getSatelliteContentComponent()); undockedSatelliteContentPanel.add(graphComponent.getSatelliteContentComponent());
undockedSatelliteContentPanel.validate(); 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 * 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 * a result of true means that the satellite is docked. If the component is not yet