mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GT-3020-dragonmacher-fg-edges-lose-alpha'
This commit is contained in:
commit
e36b22d268
23 changed files with 581 additions and 282 deletions
|
@ -19,6 +19,16 @@ import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
|
|||
import ghidra.graph.viewer.VisualEdge;
|
||||
import ghidra.program.model.symbol.FlowType;
|
||||
|
||||
/**
|
||||
* This version of the {@link VisualEdge} adds a few methods.
|
||||
*
|
||||
* <p>The {@link #setDefaultAlpha(double)} method was added here instead of the base interface, as it
|
||||
* was not needed any higher at the time of writing. It can be pulled-up, but there is most
|
||||
* likely a better pattern for specifying visual attributes of an edge. If we find we need more
|
||||
* methods like this, then that is a good time for a refactor to change how we manipulate
|
||||
* rending attributes from various parts of the API (e.g., from the layouts and from animation
|
||||
* jobs).
|
||||
*/
|
||||
public interface FGEdge extends VisualEdge<FGVertex> {
|
||||
|
||||
public FlowType getFlowType();
|
||||
|
@ -27,6 +37,30 @@ public interface FGEdge extends VisualEdge<FGVertex> {
|
|||
|
||||
public void setLabel(String label);
|
||||
|
||||
/**
|
||||
* Set this edge's base alpha, which determines how much of the edge is visible/see through.
|
||||
* 0 is completely transparent.
|
||||
*
|
||||
* <P>This differs from {@link #setAlpha(double)} in that the latter is used for
|
||||
* temporary display effects. This method is used to set the alpha value for the edge when
|
||||
* it is not part of a temporary display effect.
|
||||
*
|
||||
* @param alpha the alpha value
|
||||
*/
|
||||
public void setDefaultAlpha(double alpha);
|
||||
|
||||
/**
|
||||
* Set this edge's base alpha, which determines how much of the edge is visible/see through.
|
||||
* 0 is completely transparent.
|
||||
*
|
||||
* <P>This differs from {@link #getAlpha()} in that the latter is used for
|
||||
* temporary display effects. This method is used to set the alpha value for the edge when
|
||||
* it is not part of a temporary display effect.
|
||||
*
|
||||
* @return the alpha value
|
||||
*/
|
||||
public double getDefaultAlpha();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// Suppressing warning on the return type; we know our class is the right type
|
||||
@Override
|
||||
|
|
|
@ -34,10 +34,12 @@ public class FGEdgeImpl implements FGEdge {
|
|||
boolean doHashCode = true;
|
||||
int hashCode;
|
||||
|
||||
private boolean inActivePath = false;
|
||||
private boolean inHoveredPath = false;
|
||||
private boolean inFocusedPath = false;
|
||||
private boolean selected = false;
|
||||
private double emphasis = 0D;
|
||||
private double alpha = 1D;
|
||||
private double defaultAlpha = 1D;
|
||||
private double alpha = defaultAlpha;
|
||||
private String edgeLabel = null;
|
||||
|
||||
public FGEdgeImpl(FGVertex startVertex, FGVertex destinationVertex, FlowType flowType,
|
||||
|
@ -50,13 +52,23 @@ public class FGEdgeImpl implements FGEdge {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isInActivePath() {
|
||||
return inActivePath;
|
||||
public boolean isInHoveredVertexPath() {
|
||||
return inHoveredPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInActivePath(boolean inActivePath) {
|
||||
this.inActivePath = inActivePath;
|
||||
public boolean isInFocusedVertexPath() {
|
||||
return inFocusedPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInHoveredVertexPath(boolean inPath) {
|
||||
this.inHoveredPath = inPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInFocusedVertexPath(boolean inPath) {
|
||||
this.inFocusedPath = inPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,6 +101,17 @@ public class FGEdgeImpl implements FGEdge {
|
|||
return alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultAlpha(double alpha) {
|
||||
this.defaultAlpha = alpha;
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDefaultAlpha() {
|
||||
return defaultAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point2D> getArticulationPoints() {
|
||||
return layoutArticulationPoints;
|
||||
|
@ -135,7 +158,9 @@ public class FGEdgeImpl implements FGEdge {
|
|||
newEdge.layoutArticulationPoints = newPoints;
|
||||
|
||||
newEdge.alpha = alpha;
|
||||
newEdge.inActivePath = inActivePath;
|
||||
newEdge.defaultAlpha = defaultAlpha;
|
||||
newEdge.inHoveredPath = inHoveredPath;
|
||||
newEdge.inFocusedPath = inFocusedPath;
|
||||
newEdge.selected = selected;
|
||||
return newEdge;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
|
|||
*/
|
||||
AbstractGroupingFunctionGraphJob(FGController controller,
|
||||
GroupedFunctionGraphVertex groupVertex, Set<FGVertex> newVertices,
|
||||
Set<FGVertex> verticesToRemove, boolean relayloutOverride, boolean useAnimation) {
|
||||
Set<FGVertex> verticesToRemove, boolean relayoutOverride, boolean useAnimation) {
|
||||
|
||||
super(controller, useAnimation);
|
||||
|
||||
|
@ -87,7 +87,7 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
|
|||
FunctionGraphOptions options = controller.getFunctionGraphOptions();
|
||||
RelayoutOption relayoutOption = options.getRelayoutOption();
|
||||
this.relayout = relayoutOption == VERTEX_GROUPING_CHANGES || relayoutOption == ALWAYS ||
|
||||
relayloutOverride;
|
||||
relayoutOverride;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -158,7 +158,7 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
|
|||
return positions;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Subclasses must return locations for vertices. This method will be called when no
|
||||
* relayout will be performed.
|
||||
*
|
||||
|
@ -191,15 +191,21 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
|
|||
|
||||
@Override
|
||||
protected void updateOpacity(double percentComplete) {
|
||||
|
||||
double oldComponentsAlpha = 1.0 - percentComplete;
|
||||
|
||||
Collection<FGVertex> vertices = getVerticesToBeRemoved();
|
||||
for (FGVertex vertex : vertices) {
|
||||
|
||||
vertex.setAlpha(oldComponentsAlpha);
|
||||
|
||||
Collection<FGEdge> edges = getEdges(vertex);
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(oldComponentsAlpha);
|
||||
|
||||
// don't go past the alpha when removing
|
||||
double defaultAlpha = edge.getDefaultAlpha();
|
||||
double alpha = Math.min(oldComponentsAlpha, defaultAlpha);
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +216,11 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
|
|||
|
||||
Collection<FGEdge> edges = getEdges(vertex);
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(newComponentsAlpha);
|
||||
|
||||
// don't go past the alpha when adding
|
||||
double defaultAlpha = edge.getDefaultAlpha();
|
||||
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.awt.Rectangle;
|
|||
import java.awt.geom.Point2D;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.jdesktop.animation.timing.Animator;
|
||||
import org.jdesktop.animation.timing.interpolation.PropertySetter;
|
||||
|
||||
|
@ -197,22 +198,25 @@ public class MergeVertexFunctionGraphJob extends AbstractAnimatorJob {
|
|||
parentVertex.setAlpha(oldComponentsAlpha);
|
||||
childVertex.setAlpha(oldComponentsAlpha);
|
||||
|
||||
Collection<FGEdge> edges = getEdges(parentVertex);
|
||||
Iterable<FGEdge> edges =
|
||||
IterableUtils.chainedIterable(getEdges(parentVertex), getEdges(childVertex));
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(oldComponentsAlpha);
|
||||
}
|
||||
|
||||
edges = getEdges(childVertex);
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(oldComponentsAlpha);
|
||||
// don't go past the alpha when removing
|
||||
double defaultAlpha = edge.getDefaultAlpha();
|
||||
double alpha = Math.min(oldComponentsAlpha, defaultAlpha);
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
|
||||
double newComponentsAlpha = percentComplete;
|
||||
mergedVertex.setAlpha(newComponentsAlpha);
|
||||
|
||||
edges = getEdges(mergedVertex);
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(newComponentsAlpha);
|
||||
|
||||
// don't go past the alpha when adding
|
||||
double defaultAlpha = edge.getDefaultAlpha();
|
||||
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.awt.Rectangle;
|
|||
import java.awt.geom.Point2D;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.jdesktop.animation.timing.Animator;
|
||||
import org.jdesktop.animation.timing.interpolation.PropertySetter;
|
||||
|
||||
|
@ -114,9 +115,21 @@ public class SplitVertexFunctionGraphJob extends AbstractAnimatorJob {
|
|||
|
||||
controller.synchronizeProgramLocationAfterEdit();
|
||||
|
||||
restoreEdgeDisplayAttributes();
|
||||
|
||||
viewer.repaint();
|
||||
}
|
||||
|
||||
private void restoreEdgeDisplayAttributes() {
|
||||
|
||||
Iterable<FGEdge> edges =
|
||||
IterableUtils.chainedIterable(getEdges(parentVertex), getEdges(childVertex));
|
||||
for (FGEdge edge : edges) {
|
||||
double alpha = edge.getDefaultAlpha();
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPercentComplete(double percentComplete) {
|
||||
trace("setPercentComplete() callback: " + percentComplete);
|
||||
updateNewVertexPositions(percentComplete);
|
||||
|
@ -214,7 +227,11 @@ public class SplitVertexFunctionGraphJob extends AbstractAnimatorJob {
|
|||
|
||||
Collection<FGEdge> edges = getEdges(toSplitVertex);
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(oldComponentsAlpha);
|
||||
|
||||
// don't go past the alpha when removing
|
||||
double defaultAlpha = edge.getDefaultAlpha();
|
||||
double alpha = Math.min(oldComponentsAlpha, defaultAlpha);
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
|
||||
double newComponentsAlpha = percentComplete;
|
||||
|
@ -223,12 +240,19 @@ public class SplitVertexFunctionGraphJob extends AbstractAnimatorJob {
|
|||
|
||||
edges = getEdges(parentVertex);
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(newComponentsAlpha);
|
||||
|
||||
// don't go past the alpha when adding
|
||||
double defaultAlpha = edge.getDefaultAlpha();
|
||||
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
|
||||
edges = getEdges(childVertex);
|
||||
for (FGEdge edge : edges) {
|
||||
edge.setAlpha(newComponentsAlpha);
|
||||
// don't go past the alpha when adding
|
||||
double defaultAlpha = edge.getDefaultAlpha();
|
||||
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
|
||||
edge.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.awt.Color;
|
|||
import java.awt.geom.Point2D;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.junit.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
|
@ -37,6 +38,7 @@ import ghidra.framework.plugintool.util.PluginException;
|
|||
import ghidra.graph.viewer.options.RelayoutOption;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import util.CollectionUtils;
|
||||
|
||||
public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||
|
||||
|
@ -809,14 +811,41 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||
verifyDefaultColor(v2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEdgeDefaultAlphaPersistsAfterGrouping() {
|
||||
|
||||
graphFunction("01002cf5");
|
||||
|
||||
FGVertex v1 = vertex("01002cf5");
|
||||
FGVertex v2 = vertex("01002d0f");
|
||||
|
||||
FunctionGraph graph = getFunctionGraph();
|
||||
Iterable<FGEdge> edges = graph.getEdges(v1, v2);
|
||||
assertEquals(1, IterableUtils.size(edges));
|
||||
FGEdge edge = CollectionUtils.any(edges);
|
||||
|
||||
Double alpha = edge.getAlpha();
|
||||
assertTrue(alpha < 1.0); // this is the default flow
|
||||
|
||||
GroupedFunctionGraphVertex group = group("A", v1, v2);
|
||||
ungroup(group);
|
||||
|
||||
edges = graph.getEdges(v1, v2);
|
||||
assertEquals(1, IterableUtils.size(edges));
|
||||
edge = CollectionUtils.any(edges);
|
||||
|
||||
Double alphAfterGroup = edge.getAlpha();
|
||||
assertEquals(alpha, alphAfterGroup);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSymbolAddedWhenGrouped_SymbolOutsideOfGroupNode() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
||||
// @formatter:off
|
||||
@Override
|
||||
|
|
|
@ -313,7 +313,7 @@ public class TestFGLayoutProvider extends FGLayoutProvider {
|
|||
}
|
||||
|
||||
else if (startCol.index > endCol.index) { // flow return
|
||||
e.setAlpha(.25);
|
||||
e.setDefaultAlpha(.25);
|
||||
|
||||
Shape shape = transformer.apply(startVertex);
|
||||
Rectangle bounds = shape.getBounds();
|
||||
|
@ -338,7 +338,7 @@ public class TestFGLayoutProvider extends FGLayoutProvider {
|
|||
|
||||
else { // same column--nothing to route
|
||||
// straight line, which is the default
|
||||
e.setAlpha(.25);
|
||||
e.setDefaultAlpha(.25);
|
||||
}
|
||||
newEdgeArticulations.put(e, articulations);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue